在众多HTTP CODE 里,作为一名程序员我们都喜欢200,但从不喜欢以5xx打头的HTTP返回码,比如502,注意不是520。发生大量502报警,你会不会紧张,比如下面这张图。平时为0,很短时间内达到3w+。
再比如,域名流量监控下,一旦洪峰流量过来,你会不会紧张。比如下图所示,平时只有1、2百兆的流量,突然达到了2、3G的流量。
在同步应用下有一条“故障神经线”,一旦触发就会让你神经紧张。这条神经线是这么建立的:用户请求通过NGINX接入进来,首先抵达A系统,通过RPC的方式A系统去调用B系统。如下图所示。
造成502最为常见的原因是故障依赖传导,因为是同步调用,故障就会顺着一层层的依赖关系反映到表层,正如上面这张调用链图所示,从系统B传导到系统A再通过VIP传导到最终用户。
形成这种“故障神经线”的原因,大致如下:
1、B系统变慢,可能原因是业务逻辑处理性能下降,也有可能是B系统依赖的资源出现性能问题。
2、A系统和B系统之间的网络出现问题,比如抖动、发生大量TCP重传。
3、因为上述1和2的原因,A系统对B系统采取了容错处理,比如限流、禁用,来防止故障扩大化。最要命的一点是,被限制了的请求发生重试,因为最外层的调用方一旦请求受限,他们可能会疯狂的重试,造成流量洪峰,如上面第二张图所示。
4、由于系统A做了容错保护,比如线程池固定在了1000大小,那么在这样洪峰的情况下,因为重试处理不过来的请求,直接通过Nginx以大量502的HTTP状态码反映到用户,如上面第一张图所示。
这期间还有可能会造成如下问题:
1、分布式限流遭受热点
一般我们实现分布式限流都是通过redis的方式解决。如果发生了某一个固定用户且有很多台服务器的疯狂重试请求,因为单一的KEY的请求落到了一个redis集群分片上,就会触发热点。一般2C10G大小内存的一个分片,80000次/秒的请求,就会触发我们事先设置好的热点阈值了。
当上述这种分布式限流遇到瓶颈的时候,就需要考虑降级到单机服务器限流,程序代码从本机的缓存中读取限流的配置信息来进行限流的处理。
无论采用哪种限流方案都没有好坏之分,只有符合自己业务场景的限流方案,而且能使用最小的成本来有效的解决技术上的难点,就是最好的方案。
2、TCP重传次数过高
TCP是一种可靠的传输通讯协议,正是为了保证这样的传输可靠性,有了重传这样的机制。它的原理是当发送一个报文后,会开启一个超时重传计时器 (Retransmission Timer , RTT),注意是计时不是计数器。如果在这个计时范围内没有收到来自目的接收方的确认,发送端就会启动这样的重传机制。如下图所示,就是TCP重传监控的一个例子。
导致出现重传的原因大致有如下几种情况:
网络故障
如果两个通讯服务端点之间发生了丢包、频繁抖动等网络故障,如果网络质量不能较好的保障,根据TCP重传机制的理解,从而出现TCP重传的概率就会比较高。
服务器端口SPEED设置不合理
两台服务器A和B,服务器B为TCP传输的目标服务器,此时如果服务器A的端口速率speed是1000Mb/S,服务器B的端口速率speed是10Mb/S,那么因为目标服务器的速率太小,则会造成TCP重传。
请求速度远远大于响应速度
可能原因是接收请求处理的一方处理速度确实变慢,还有种可能是服务端处理的集群能力已经达到了极限。这两种原因都会导致请求发送的一方触发TCP重传。
说回502
除了上面开始介绍的服务器发生502的原因,还有其他原因可以造成502。比如防火墙阻止请求,因为某些DDos保护系统过度反应而阻止了系统的请求。网络发生错误,比如DNS问题,路由问题以及和ISP相关的问题等也可以导致502的发生。
但我们日常线上一旦发生大量502错误报警的时候,我们还是要首先排除服务系统的故障,502的本质原因,对于用户来讲就是访问请求的响应超时造成的。
异步能不能解决这种问题
一般RPC异步模式都使用队列或MAP来实现,然后用一个事件循环线程不停地轮询队列事件。这样的模式下可以接收很多的请求并直接放入队列,当有事件发生的时候,通过触发回调函数来处理事件。由于使用的线程较少,切换开销也少,也就基本不会有多线程阻塞的问题,如下图所示。
上图,及描述参考《架构修炼之道》
还是以本文第三张调用图为例来阐述,系统A通过异步来调用系统B,对于系统A来讲不需要等待,来了请求就直接调用到系统B,响应结果由事件循环发现处理并返回最终用户。
那么这样会造成一个问题,如果请求量短时间内非常大对系统B就是一个冲击,对系统A的内存队列也是一个考验。如果系统B迟迟仍然不能将最终要的响应结果返回的话,对于最终用户这一端仍然是要发起重试。
所以异步调用在短时间内大量请求过来的情况下也只是能缓解上述我们说的问题。
采用异步调用可以大大减少调用方集群的服务器数量,它能够耗费很少量的资源去发起更多的请求,在大流量平稳调用下这是很好的处理方式,尤其是在网关应用中。
但极端流量请求下,如遇到分布式限流这样的情况,也还是会遇到上面我们已经阐述的热点问题。同事也还会遇到刚刚提到的内存问题,对下游的冲击问题。但是,异步在合适的场景下仍然是一个趋势。
总结
一线研发人员不可能不跟线上问题打交道,会时长走在解决问题的路上,本文所讲述的这条故障神经线,也是其中之一。我们从502现象开始说起,剖析了这条故障线的发生到表象,以及这个过程中触发的问题点比如分布式限流热点问题,TCP重传问题。积累经验,砥砺前行。