三年多前,我在腾讯负责的活动运营系统,因为业务流量规模的数倍增长,系统出现了各种各样的异常,当时,作为开发的我,7*24小时地没日没夜处理告警,周末和凌晨也经常上线,疲于奔命。后来,当时的老领导对我说:你不能总扮演一个“救火队长”的角色, 要尝试从系统整体层面思考产生问题的根本原因,然后推进解决。
我幡然醒悟,“火”是永远救不完的,让系统能够自动”灭火”,才是解决问题的正确方向。简而言之,系统的异常不能总是依赖于“人”去恢复,让系统本身具备“容错”能力,才是根本解决之道。三年多过去了,我仍然负责着这个系统,而它也已经从一个日请求百万级的小Web系统,逐步成长为一个高峰日请求达到8亿规模的平台级系统,走过一段令人难忘的技术历程。
容错其实是系统健壮性的重要指标之一,而本文会主要聚焦于“容错”能力的实践,希望对做技术的同学有所启发和帮助。
(备注:QQ会员活动运营平台,后面统一简称AMS)
简单重试机制
最容易也最简单被人想到的容错方式,当然就是“失败重试”,总而言之,简单粗暴!简单是指它的实现通常很简单,粗暴则是指使用不当,很可能会带来系统“雪崩”的风险,因为重试意味着对后端服务的双倍请求。
我们请求一个服务,如果服务请求失败,则重试一次。假设,这个服务在常规状态下是99.9%的成功率,因为某一次波动性的异常,成功率下跌到95%,那么如果有重试机制,那么成功率大概还能保持在99.75%。而简单重试的缺陷也很明显,如果服务真的出问题,很可能带来双倍流量,冲击服务系统,有可能直接将服务冲垮。而在实际的真实业务场景,往往更严重,一个功能不可用,往往更容易引起用户的“反复点击”,反而制造更大规模的流量冲击。比起服务的成功率比较低,系统直接被冲击到“挂掉”的后果明显更严重。
简单重试,要使用在恰当的场景。或者,主动计算服务成功率,成功率过低,就直接不做重试行为,避免带来过高的流量冲击。
主备服务自动切换
既然单一服务的重试,可能会给该带来双倍的流量冲击,而最终导致更严重的后果,那么我们不如将场景变为主备服务的自动重试或者切换。例如,我们搭建了两套获取openid的服务,如果服务A获取失败,则尝试从服务B中获取。因为重试的请求压力是压到了服务B上,服务A通常不会因为重试而产生双倍的流量冲击。
这种重试的机制,看似比较可用,而实际上也存在一些问题:
(1) 通常会存在“资源浪费”的问题。因为备份服务系统,很可能长期处于闲置状态,只有在主服务异常的时候,它的资源才会被比较充分地使用。不过,如果对于核心的服务业务(例如核心数据、营收相关)进行类似的部署,虽然会增加一些机器成本和预算,但这个付出通常也是物有所值的。
(2) 触发重试机制,对于用户的请求来说,耗时必然增加。主服务请求失败,然后再到备份服务请求,这个环节的请求耗时就至少翻倍增长,假设主服务出现连接(connect)超时,那么耗时就更是大幅度增加。一个服务在正常状态下,获取数据也许只要50ms,而服务的超时时间通常会设置到500-1000ms,甚至更多,一旦出现超时重试的场景,请求耗时必然大幅度增长,很可能会比较严重地影响用户体验。
(3) 主备服务一起陷入异常。如果是因为流量过大问题导致主服务异常,那么备份服务很可能也会承受不住这种级别的流量而挂掉。
重试的容错机制,在AMS上有使用,但是相对比较少,因为我们认为主备服务,还是不足够可靠。
动态剔除或恢复异常机器
在AMS里,我们的后端涉及数以百计的各类服务,来支撑整个运营系统的正常运作。所有后端服务或者存储,首先是部署为无状态的方式提供服务(一个服务通常很多台机器),然后,通过公司内的一个公共的智能路由服务L5,纳入到AMS中。
(1) 所有服务与存储,无状态路由。这样做的目的,主要是为了避免单点风险,就是避免某个服务节点挂了,导致整个服务就瘫痪了。实际上,即使像一些具有主备性质(主机器挂了,支持切换到备份机器)的接入服务,也是不够可靠的,毕竟只有2台,它们都挂了的情况,还是可能发生的。我们后端的服务,通常都以一组机器的形式提供服务,彼此之间没有状态关系,支撑随机分配请求。
(2) 支持平行扩容。遇到大流量场景,支持加机器扩容。
(3) 自动剔除异常机器。在我们的路由服务,发现某个服务的机器异常的时候(成功率低于50%),就会自动剔除该机器,后续,会发出试探性的请求,确认等它恢复正常之后,再重新加回到服务机器组。
例如,假如一组服务下拥有服务机器四台(ABCD),假设A机器的服务因为某种未知原因,完全不可用了,这个时候L5服务会主动将A机器自动从服务组里剔除,只保留BCD三台机器对外提供服务。而在后续,假如A机器从异常中恢复了,那么L5再主动将机器A加回来,最后,又变成ABCD四台机器对外提供服务。
在过去的3年里,我们逐步将AMS内的服务,渐渐从写死IP列表或者主备状态的服务,全部升级和优化为L5模式的服务,慢慢实现了AMS后端服务的自我容错能力。至少,我们已经比较少遇到,再因为某一台机器的软件或者硬件故障,而不得不人工介入处理的情况。我们也慢慢地从疲于奔命地处理告警的苦难中,被解放出来。
对于web系统容错机制,还有超时时间、服务解耦等一系列方法将在下篇文章总结。
领取专属 10元无门槛券
私享最新 技术干货