继去年双11之后,支付宝又P0事故了!!还是在绩效开奖之前的重要节点,恐怕会有一批程序员的年不好过了。这次事故直接导致所有订单减免20%,甚至转账都进行了“补贴”,对于支付宝这样的国民级应用,损失不可估量。
今天真的有必要来聊一聊故障和风险管理,尤其是在支付行业。
故障频发的背后,是对故障和风险的把控,今天特地邀请一位支付宝的支付专家来聊一聊故障和风险的顶层设计。
先声明:这位专家和上面的故障没有关系,不是同一个部门,在他的带领下,他所在的团队一直保持极低的故障率,来看看他是怎么做的。这是大佬的公众号,也可以关注一下。
没有人可以打包票说:“我设计的系统一定不会出问题”,哪怕已经做了各种高可用设计,故障还是防不胜防。在系统高可用和故障保障方面有什么顶层设计?
要做好系统保障,必先理解其本质。故障的本质是风险,风险发生了叫故障,没发生叫潜在风险。所有的风险都有概率性,关键不在于彻底消除风险,而在于控制风险的实际影响。更直接地说,不是不允许犯错,而是避免犯大错,这是系统保障的核心理念。
对于一个由风险导致的故障X,我们如何度量其影响E(X)?我们可以从以下五个方面来分析。
风险点的数量,记为N。持续为用户提供服务的生产系统,如果不进行变更,通常不会出现问题。一旦进行代码发布或配置变更。就易引入风险。从风险防常布发来看,不变更是最稳定、最不容易出问题的状态。但这不切实际,因为安更意味着不会给用户提供新功能、也意味着业务不会有任何发展。因此,管风险点的数量就是要对不必要的变更进行限制,比如,不在业务高峰期或重大假日进行变更。
风险发生的概率,记为P(X) 。不可否认,对生产系统进行变更就会引入风险,但我们可以通过建立流程制度和编写高质量代码来降低风险发生的概率。在研发流程中加强测试,进行小流量的功能验证,都是通过流程制度来降低风险发生率的方法。同样,防御式编程和严谨的异常逻辑处理也是通过提高编码质量来低风险发生概率的方法。
风险变为故障后影响的范围大小,记为 R(X) 。当概率性风险变为实际故障后,首要任务是控制故障的影响范围。故障影响范围的控制也需要在架构设计中提前考虑。
风险变为故障后影响的程度大小,记为F(X) 。一个系统承载了多种不同的业务,不同业务的重要性和优先级也不相同。当系统面临风险时,不能一刀切而是要做好取舍,确保高等级业务不受影响。
风险变为故障后影响的时间长短,记为T(X) 。故障的影响程度还有一个非常重要的变量,即故障发生的时间长短,故障时间越长,影响越大。在架构设计上有许多案例旨在降低这个因素。
综上所述,系统保障的目标就是降低风险转化为故障后的影响值E(X),其数学公式可以表示为:
上面的公式有效地指出了系统保障的方法,降低故障影响值E(X)就是降低上述五个因素的值。基于此,我们可以提炼出系统保障的四大设计原则
降低故障的影响半径,即减小故障的影响范围,核心在于做好故障点的自我隔离。只要故障点能够自我隔离,即使故障爆发得再严重,也不会对整体系统造成太大的影响。做好故障点的自我隔离可以通过水平和垂直两个角度来考虑。
水平视角的隔离,最经典的做法是采用分散设计,将资源分散为N份,这样单份出现故障的影响就只有1/N。这种方法实质上是在减小风险变故障后影响的范围大小R(X)的值。分散设计在多个层面上都有应用,例如在软件架构层面,可以从单机系统架构转变为分布式系统架构;在数据库设计层面,可以从单库单表设计转变为分库分表设计;在硬件资源层面,可以从同城双中心部署转变为跨洲多中心部署。
垂直视角的隔离,最典型的做法是采用弱依赖设计。 减少在整条链路上强依赖的系统,即使被依赖的系统出现问题,也不会导致整体故障。典型的架构设计方法是:将同步调用转变为异步调用,以减少下游系统的阻塞带来的容量和性能风险。例如:在支付系统中,与外部银行或支付机构的交互可以设计为同步受理请求异步通知消息,通过消息来推进支付状态。这种松合的设计能够规避外部系统故障导致自身系统宕机的风险。
降低故障影响程度F(X)的关键在于识别提供服务的重要性和优先级,以便在真正的故障发生时,能够优先保护重要的服务。为了保护重要的服务,最关键的架构设计包括限流和降级两个方面。
限流设计就像是“一夫当关,万夫莫开”。 在互联网系统中,特别是在双十一大促等高流量场景下,即使是最强大的系统,如阿里的系统,能够支持几十万的TPS,用户也可能会看到“请稍后重试”的提示。这其实是系统为了防止大流量击垮系统而采取的限流措施。通过在系统的最短路径上拒绝部分流量,将系统无法处理的巨量流量拦截在外,以保护内部系统的稳定性。
在系统架构上,实现限流的方法有很多,例如,使用Nginx的限流功能Redis的全局计数器、Token桶算法等。
降级设计则像是“舍车保帅”。当整体系统受到影响时,通过降级部分系统或业务,以确保核心业务不受影响,仍然能够正常提供服务。例如,在双十一大促的流量高峰期,用户会看到蚂蚁森林能量生成可能会延迟的公告。这实际上是在流量高峰时,对蚂蚁森林的服务时效性进行了降级,以确保支付功能的高可用性。
在系统架构上,实现级的方法包括梳理清楚可以降级的功能和系统链路并在入口处设置开关。当真正发生高可用风险时,可以通过这些开关直接降级部分功能,以保护系统的核心服务。
去单点实质上是在故障发生时能够迅速采取措施以止血或切换,其核心思是通过快速应急切换,缩短故障影响的时间,即减小T(X)。去单点在架构设计的主要方法是冗余备份。一个典型的例子是OceanBase 的多节点设计,只要超过半数的节点存活,就能保证整体服务的可用性。这也是分布式系统的常见做法,尤其是在一些去中心化的区块链应用中。
系统自愈是指当系统出现高可用性问题时,系统能够自动关联设计的预案并执行,而不需要人工干预。例如,账务系统中可能会出现账户热点问题,即一个户的记账请求并发量过高导致记账失败,如果这个问题不处理,则可能会导致记账线程阻塞,进而导致系统资源耗尽和高可用性故障。在架构设计上,可以通过对热点账户进行统计,当达到某个阈值时自动对热点账户进行限流。通过这种方式,当热点账户出现异常时、系统能够自动愈合,从而规避高可用性风险。
在降低风险发生概率P(X)方面,特别是涉及有人参与的系统变更,仅仅依靠系统架构的改进是不够的。这些风险往往无法通过架构设计完全规避,因此需要流程制度的配合。一个关键的流程制度是生产环境故障的变更流程规范,可以总结为“三板斧”:可灰度、可监控、可应急。
可灰度的核心是变更需要分批执行,从小规模开始逐步验证和观察,直到确认没有问题后才会全面实施变更。 在系统架构设计中,采用分散设计可以在系统上植入灰度能力,但可灰度对于系统变更来说仍然至关重要,因为并非所有变更都能通过系统分散设计来解决。
可灰度变更策略的核心在于我们认识到人可能会犯错,但又不能犯大错误。然而,在执行可灰度策略时也存在一些盲区,特别需要关注以下两点:
可监控是风险变故障的“眼睛”。通过有效的监控,可以在问题发生时及时发现并采取措施,从而避免造成严重的影响。同样,可监控也要注意两点。
可应急指的是在故障真正发生时,能够迅速执行预先制定好的应急预案。在故障发生时,通常情况都是紧张而混乱的,没有提前准备,临时现场想方案是不现实的,“预则立不预则废”,因此预先准备是至关重要的。对于可应急,有两点需要特别注意:
“可以看出在这一次的支付宝事故中,还是做了监控和故障应急预案的,因此可以在故障发生时最短的时间内(5min)完成故障恢复。否则任由故障蔓延下去,严重的话可能直接把公司干倒闭。到时有多少程序员祭天都来不及了。
系统保障是一个综合而复杂的课题,它不仅仅涉及技术架构的问题,更重要的是人的参与。任何需要人工介入而非完全依赖机器规则化执行的任务都会变得非常复杂。因此,把对高可用性保障的认知,从严格防范风险转变为降低风险影响是至关重要的。通过深入思考如何降低风险对系统的影响,我们可以优化系统架构设计和流程制度。这种持续的优化过程将逐步构建起一套体系化且高效的高可用性保障体系,为系统的稳定性提供坚实的保障。
同时,每一个人也需要保持对生产环境的敬畏之心,每一次发布,每一次变更,都不要当做是小事,需谨慎对待。