前言
Java应用正常发布上线时第一次请求往往会比较耗时,时长会达到几百毫秒甚至秒级,那么会比较容易触发consumer服务超时,用户体验会受损。在高并发场景下还有可能会出现雪崩效应导致整个集群不可用
传统模式
传统微服务上线过程
通常情况下我们服务发布按照滚动发布或者分批发布方式进行发布上线,这样的方式发布服务上线了就会等比承载流量,以下图为例A服务有4个节点,按照负载均衡的逻辑每个节点承载25%的流量。当其中一个节点开始发布切换到v2版本过程中有25%的流量会分摊到其他三个节点,v2版本成功发布后单节点会立马承载25%流量。这是我们最常使用的发布方式。
传统微服务上线缺点
我们都知道java应用方法要被执行时,首先这个方法所在的类需要被JVM加载,这个过程包括各类文件的验证、解析、链接以及类的初始化。当这个类被加载进来了以后,JVM就可以去执行这个方法。JVM在刚开始的时候会使用模板解释器去解释执行方法,模板解释器除了一个个去执行方法中的Bytecodes之外,还会额外收集关于方法执行动态运行的信息,例如方法执行的调用次数,调用时一些类型的信息等。这些信息都会提供给JVM的即时编译器,由它利用这些信息将刚才解释执行发现的热点方法编译成为Native Code。这样JVM就不用模板解释器去执行这些方法,而是去执行性能更高的Native Code,从而使应用程序的性能得到大幅提升。由此可见我们服务启动成功并不能获得最佳性能,需要一段时间预热,所以当A服务v2版本上线刚上线那段时间会如前言描述比较容易导致超时,甚至在毛刺期间可能会导致服务雪崩效应。那么如何解决呢?我们接着往下看
Warmup方案
目前业界有两种方案第一种是阿里开源的Dragonwell JDK提供的JWarmup方案,第二种是基于Uptime思路去做,本文会主要介绍此方案。
什么是Uptime
上线时间(Uptime)是指某时间段内计算机或通信系统正常工作的总时长
Uptime如何实现
通常情况下我们可以利用Api网关和RPC框架LoadBalance的能力基于上线时间来进行流量预热,服务刚上线时分配极小流量,随着新服务上线总时长不断增长,流量也需要等比增长,用这种方式最大程度提升用户体验和降低服务雪崩风险
Dubbo Uptime实现
目前在RPC框架中Dubbo已经有现成的实现,主要实现逻辑是计算权重保证当服务运行时长小于服务预热时间时,对服务进行降权,避免让服务在启动之初就处于高负载状态,慢慢让服务处理最佳状态。Dubbo具体实现代码如下:
protected int getWeight(Invoker<?> invoker, Invocation invocation) {
// 从 url 中获取权重 weight 配置值
int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT);
if (weight > 0) {
// 获取服务提供者启动时间戳
long timestamp = invoker.getUrl().getParameter(Constants.REMOTE_TIMESTAMP_KEY, 0L);
if (timestamp > 0L) {
// 计算服务提供者运行时长
int uptime = (int) (System.currentTimeMillis() - timestamp);
// 获取服务预热时间,默认为10分钟
int warmup = invoker.getUrl().getParameter(Constants.WARMUP_KEY, Constants.DEFAULT_WARMUP);
// 如果服务运行时间小于预热时间,则重新计算服务权重,即降权
if (uptime > 0 && uptime < warmup) {
// 重新计算服务权重
weight = calculateWarmupWeight(uptime, warmup, weight);
}
}
}
return weight;
}
static int calculateWarmupWeight(int uptime, int warmup, int weight) {
// 计算权重,下面代码逻辑上形似于 (uptime / warmup) * weight。
// 随着服务运行时间 uptime 增大,权重计算值 ww 会慢慢接近配置值 weight
int ww = (int) ((float) uptime / ((float) warmup / (float) weight));
return ww < 1 ? 1 : (ww > weight ? weight : ww);
}
总结
Warmup机制对生产还是有很大帮助的,不过SpringCloud体系还需要自行实现
欢迎关注我的微信公众号:「稳的跟座山」,关于文章的任何疑问都会得到回复,带来更多 Java 相关的技术分享。