我是乐羊,一个热爱风险防控的人,之前参与过蚂蚁 Glocal 多个站点从 0 到 1 的建站和高可用建设,目前正在参与蚂蚁大安全的高可用建设。
无论是一个域,一个 BG,还是一个站点,虽然范围有大有小,对象有所不同,但其高可用的理念都是相通的,今天将自己对高可用的一点点思考以及总结的“nPRT 公式”分享给大家。
本文采用“高可用是什么,为什么要高可用,怎么做高可用,为什么这么做,软件风险又在哪里”的逻辑来介绍。
高可用是一种面向风险设计,使系统具备控制风险,提供更高的可用性的能力。
对于一个公司而言,“为什么要高可用”可以完整理解为“公司为什么要(做系统)高可用”。
以公司为对象,从内看包括:人,软件(物),硬件(物);从外看包括:客户,股东,社会;从自身看包括:公司。
高可用的大前提,所有事物都不是 100% 可靠的:
-
所有事物都是变化的(唯一不变的是变化)。
-
所有变化的都不是 100% 可靠的。
-
结论:所有事物都不是 100% 可靠的。
-
从人的层面:
人都是有可能犯错的。
-
从软件层面:
软件都是有可能有 Bug 的。
-
从硬件层面:
硬件都是有可能会坏的。
从概率学角度分析,凡是有可能会出错的,只要变化次数足够多,最终出错的概率会无限趋向于 1。
-
从客户角度:无高可用,客户服务可能会中断。
-
从股东层面:无高可用,股价可能会下跌。
-
从社会角度:无高可用,社会秩序可能受影响。
根因(本质):控制风险。
从公司自身角度:控制风险,保障公司价值,避免伤及根本。
如何做高可用,本质上就是:如何控制风险。
风险:
指未来会发生危害的一种可能性,但实际未发生,记为r。
故障:
指已发生或正在发生危害的一种事实,是风险变现实的结果。
风险概率:
指一个风险变故障的概率。用它来表示风险触发为故障的难易程度,记为 P(r)。
故障影响范围:
指在单位时间内,一个故障造成的危害影响,记为 R(r)。
故障影响时长:
指一个故障持续的时间,记为 T(r)。
故障影响面:
指一个故障影响范围乘以故障影响时长的总和。这里用故障影响面来表示故障总的危害程度,记为 F(r)。
风险期望:
指每个风险变故障的概率乘以每个风险变故障后的故障影响面的总和。这里用风险期望来表示风险的潜在危害程度,记为 E(r)。
r 代表风险,风险期望会随着风险的数量 n 和每个风险的 P、R、T 下降而下降,简称 nPRT 公式。(注:如果要引用该公式请注明出处。)
①减少风险数量,n
从源头远离风险,做到与风险载体无连接,无关系;那么该风险概率就是0,也不关心该风险发生后的故障影响面是大是小,完全不关心。
例如:重大节日活动,施行全站封网,变更的数量就会得到一个明显的下降,就是典型的减少风险数量。
例如:系统 A 完全不依赖 Oracle,那系统 A 就不用关心 Oracle 的任何风险,哪怕美国总统突然紧急宣布 Oracle 立即立刻禁止在中国使用,系统 A 也无所谓。
例如:最近新冠大流行,人传人很可怕,如果你今天选择不上班不出门,那你今天就不用担心被外面的行人和同事传染。
②降低风险变故障的概率(即:增加风险变故障的难度),P
把风险当成一个对象看待,给它层层设卡,增加风险变故障的门槛和难度,不要再让“不小心多了一个空格或字符,系统就挂了”这种惨案轻易出现。
例如:人员 B 要对系统 C 进行变更,可以对人员 B 增加变更认证考试,对变更内容要求线下(或仿真)测试,对变更内容进行 CR,系统 C 提供变更效果预览能力(类似监控模式或试运行)。
万一人员 B 想恶意变更搞破坏,还可以增加非同人复核,系统C可以增加防错设计进行保护等等。
例如:以新冠为例,带口罩,勤洗手,多通风等就可以降低染上新冠的概率。
③减小故障影响范围,R
以大拆小,将一个整体拆分成 N 个小的个体,每个个体之间进行相互隔离,单个个体出问题仅影响单个个体,实现小而美。
例如:分布式架构就是这个的典范,集中式一损俱损,分布式一损即 N 分之一损。
例如:以新冠为例,网格化管理,各省或市间的流动进行限制,跨省必须核酸+隔离 14 天,有效控制新冠的传播范围。
④缩短故障影响时长,T
故障影响时长由故障发现时间和故障止血时间决定,所以要早发现早止血。
发现方式分为:
事前的预警,事后的告警。尽可能朝事前预警去做,给止血争取时间甚至将风险扼杀在摇篮中。
止血方式分为:
切换,回滚,扩容,降级 or 限流,BUG 修复等。故障出现时第一优先原则为快速止血(如切换、回滚、扩容),严禁去定位根因;当无法快速止血时以少流血为第二优先原则,如降级、限流。
止血效率:
自动 vs 人工 ;一键化 vs 多步操作。尽可能用自动化去代替人工操作,若人工操作时尽量实现一键化,提升止血速度。
例如:对于容量水位,可以在警戒线之前划一条预警线,提前预警,从容应对。
例如:分布式应用集群,任何一台应用服务器有问题时,负载均衡会通过心跳检查自动把有问题的应用服务器剔除,将请求转发给其他(热)备份冗余的服务器上。
例如:以新冠为例,但由于每个生命都是独一无二的,没有办法切换,也没有办法回滚,也不能降级(涉及人道主义),只能对症下药慢慢治疗。
根据 nPRT 公式,在高可用架构设计时有以下 7 个核心原则:
①少依赖原则:能不依赖的,尽可能不依赖,越少越好(n)
由于所有事物都不是 100% 可靠的,当 2 个事物之间有了关系,那么就会相互影响,就互为对方的一个风险,一个出问题可能会影响另外一个。我们统一用依赖来泛指这里的“关系”。
例如:一个系统同时依赖 Oracle,MySQL,OB 三种关系型数据库,少依赖原则是改成仅依赖最成熟稳定的 OB,不依赖 Oracle 和 MySQL。
什么场景适合多依赖?当引入依赖(n 变大)可以减小 PRT 中的一个或多个,且使 E(r) 整体下降时。
例如:为解决 DB 风险,引入分布式缓存,只要 2 者不同时挂的时候依然可用。
②弱依赖原则:一定要依赖的,尽可能弱依赖,越弱越好(P)
事物 a 强依赖事物 b,一旦 b 出问题时,那么 a 也会出问题,一损俱损。所以任何强依赖都要尽可能的转化成弱依赖,可以直接降低出问题的概率。
例如:交易核心链路在交易成功后要要给用户发放积分权益;交易核心系统需要依赖积分权益系统,好的方式是采用弱依赖,使用异步化的方式,这样积分权益系统不可用时,大概率不会影响交易核心链路。
③分散原则:鸡蛋不要放一个篮子,分散风险(R)
打散拆分成 N 份;避免全局只有 1 份,否则一有问题影响范围就是 100%。
例如:所有交易数据都放在同一个库同一张表里面,万一这个库挂了,此时影响所有交易。
例如:将自己所有的钱买了同一只股票,万一这只股票是乐视就惨了。
④均衡原则:均匀分散风险,避免不均衡(R)
最好 N 份中的每份都是均衡的;避免某个份额过大,否则过大的那份一有问题就影响范围过大了。
例如:xx 应用集群有 1000 台,但由于引流组件 Bug,导致所有流量引到了其中 100 台上面,导致负载严重不均衡,最后因负载无法扛着全面崩溃。类似重大故障已经发生了多次。
例如:将自己所有的钱买了 10 只股票,其中一只占比 99%,万一这只股票是乐视就惨了。
⑤隔离原则:控制风险不扩散,不放大(R)