大家都知道高并发系统三轴:缓存、熔断、限流。但是还有一个斧头经常被遗忘在角落里,郁闷,那就是热身。现象举例首先,让我们谈谈两个现象。这些现象只有在高并发的系统中才会出现。好吧,它导致了多个故障。1、DB重启后,瞬间死掉。高并发环境下的DB,进程挂掉后重启。由于业务高峰期,对上游负载均衡策略进行了重新分配。刚启动的DB瞬间收到了1/3的流量,然后负载疯狂飙升,直到没有任何响应。原因是:对于新启动的DB,各种??缓存还没有准备好,系统状态和正常运行时完全不一样。大概平时用量的1/10就可以把它弄死。2、服务重启后,访问不正常。另一个常见问题是我的一台服务器出现问题。由于负载均衡的作用,其余机器立即承载这些请求并运行良好。当服务重新加入集群时,会出现大量耗时请求,甚至在请求量大的情况下会出现大量失败。原因可以归结为:1、服务启动后,jvm没有准备好,JIT没有编译等。2、应用使用的各种资源没有准备好。3.负载均衡已经重新均衡。这两个问题都是因为没有预热WarmUp,也就是冷启动/预热的方式。当系统长期处于低水位,流量突然增加时,直接将系统拉到高水位可能会瞬间压垮系统。通过“冷启动”,让通过流量缓慢增加,在一定时间内逐渐增加到上限,给冷系统一个预热时间,避免冷系统不堪重负。我想要这样的曲线。而不是这个。事实比多方流量更复杂是不可预测的,这不同于流量的自然增长,或者人为的攻击——这是一个从无到有的过程。就连一些自诩超高速的部件,比如lmax的disruptor,也会在这突如其来的洪流下崩溃。最适合预热的入门级是网关。如图:node4是新启动的节点。网关中集成的负载均衡组件将能够识别这个新添加的实例,然后逐渐向这台机器增加容量,直到它真正能够承受高速流量。如果所有的请求都走网关,那一切就简单多了,还有像Sentinel这样的组件可以切入。然而现实往往不符合条件。例如:1、你的应用直接获取注册中心的信息,然后在客户端组件中进行流量分发。2、你的应用通过一些复杂的中间件和路由规则,最终定位到某个DB上。3、您的终端可能已经通过MQTT协议,直接连接到MQTT服务器。我们抽象一下,可以看到所有这些流量分发逻辑,包括网关,都可以称为客户端。也就是说,所有的预热逻辑都放在客户端,它们与负载均衡紧密耦合。解决办法是增加接口的体积。根据以上分析,通过编码手段控制所有客户端调用即可解决问题。一个简单的轮询方法1.我需要能够获取所有要调用的资源的集合,以及启动时间,冷启动配置等。2.给这些资源分配一些权重。例如最大权重为100,配置100秒后冷启动成功。如果现在是第15秒,则总权重为100*(n-1)+15。3、根据计算出的权重,进行分配,流量会随着时间的推移逐渐增加,直到与其他节点相等。4.极端情况下,我的后端只有一个实例,根本无法启动。以SpringCloud为例,我们要改变这些组件的行为。1、Ribbon的负载均衡策略。2.网关负载均衡策略。好在都是基础组件,不用来回copy代码。顾名思义就是提前访问所有的接口,让系统提前准备好资源。比如遍历所有的http连接,发送请求。这种方法是部分有效的。这个阶段会加载一些懒加载的资源,但不是全部。JIT等一些增强功能可能会让预热过程变得很漫长,马背上看花的方式只能起到一定的效果。再比如一些DB,在启动之后,会执行一些非常有特点的sql,从而将最需要的热点数据加载到PageCache中。状态保存系统在它死亡时拍摄快照,然后在它启动时完整地恢复它。这个过程相当神奇,因为一般的非正常关机系统是没有机会表达它的遗言的,所以只能每隔一定时间对运行中的系统进行快照。当节点启动时,快照被加载到内存中。这在一些基于内存的组件中被广泛使用。通过比较,我们发现最可靠的方式是在客户端编写并集成预热逻辑。这项工作可能是痛苦而漫长的,但结局是美好的。当然你也可以使用“移除nginx->修改权重->重新加载nginx”的方法。有时有效但不总是有效,通常令人放心但并不总是令人放心。一切都取决于你。毕竟,没有前戏就直奔主题,那叫莽撞。
