从反脆弱角度说一说:技术系统高可用性策略
1 非线性
我们先来介绍一个概念:非线性。这个概念在我们的生活中无处不在。
你要赶早上 8 点钟的火车,如果 6:30 出发可以在 7:00 到达车站,于是你得到一个结论:只要 30 分钟就可以到达车站。
你早上想睡晚一点预计 7:10 出发,想着 7:40 可以到达车站。但是最可能的结果是你将错过这趟火车。因为正好遇上早高峰,堵车导致你至少需要花费 1 个小时才能到达车站。
一个小雪球的重量是 100 克,打雪仗时你被砸中 100 次,这对你不会造成任何影响。
但是如果你被 10 公斤的雪球砸中 1 次,这可能会对你造成严重的伤害。
这就是非线性。事物不是简单的叠加关系,当达到某个临界值时,会造成一种完全截然不同的结果。
2 秒杀系统
我们来分析一个互联网的秒杀场景。假设你设计的秒杀系统当每秒 30 个人访问时,响应时间是 10 毫秒。即从用户点击按钮至得到结果这个过程,只花费了 10 毫秒。这个时间的流逝基本上察觉不到,性能是不错的。你感觉很好,继续设计:
如果你按照这个思路去做系统设计,将会发生重大的错误。因为当每秒 3000 个访问量发生时,系统的响应时间可能不是 1000 毫秒,而可能直接导致系统崩溃,无法再处理任何的请求。最常见的场景就是当缓存系统失效时,导致的系统雪崩:
当耗时低的缓存层出现故障时,流量直接打在了耗时高的数据库层,用户的等待时长就会增加
等待时长的增加导致用户更加频繁去访问,更多的流量会打在数据库层
这导致用户的等待时长进一步增加,再次导致更频繁访问
当访问量达到一个极限值时,造成系统崩溃,无法再处理任何请求
流量和响应时间绝不是简单的叠加关系,当到达某个临界值时,系统将直接崩溃。
3 黑天鹅与三体
欧洲人从来都认为只有白天鹅,因为他们从来只看到过白色的天鹅。
他们的这种想法有多坚定,那他们在澳大利亚发现黑色天鹅时,震撼就有多么大。
这就是著名的黑天鹅事件的由来。黑天鹅事件指事前无法预知,一旦发生将具有巨大影响的不确定事件。
我们来分析一下欧洲人的白天鹅理论。他们采用的是归纳推理的方法,这也是科学实验中常用的一种方法。
当他们没有见到黑天鹅之前,认为只存在白色天鹅是成立的。但当黑天鹅出现时,整个认知瞬间土崩瓦解。
一个更加值得关注的系统是混沌系统。这个系统最大的特点是,当一个微小的扰动发生时,会给整个系统带来巨大的影响。典型混沌系统的体现就是蝴蝶效应和三体问题。
一只蝴蝶挥动翅膀可以带来一场飓风。
三个天体在相互的万有引力作用下,运动轨迹无法预测,这也是刘慈欣《三体》三部曲的基础设定。
处于混沌系统,不知道黑天鹅事件将在什么时间,什么地方,以什么形式发生。
我们不知道 7 点钟出发会被堵多久,不知道秒杀系统在开抢的瞬间会有多大的访问量,不知道某大 V 在微博上公布的消息会带来多少激增的流量。
4 工程系统稳定性
我们来思考一个问题:怎样保证一个工程系统的稳定性?有以下两种做法:
思路 1:考虑到所有意外情况,针对每一个意外的异常情况分别处理
思路 2:接受无法预料到所有意外情况的现实,把兜底方案做好,保证即使出现极端情况,系统也不会崩溃
我们仔细分析思路 1 会发现这其实是一个悖论。
所谓意外情况就是意料之外的情况,无法预料的情况。如果被考虑到了,那么也就不能称之为意外情况了。
塔勒布在经典著作《反脆弱》一直想告诉我们:黑天鹅事件是无法预测的,极端意外情况是无法预测的,尾部风险虽然概率小,但破坏力却极大。
我们无法预测会发生什么故障,以及什么时候发生。但面对不确定性,我们不会束手就擒,至少可以把系统保护好。
5 高可用策略
为了保证系统的稳定性和高可用性,我们需要采取一些策略。我认为高可用核心策略一般包含:冗余+自动故障转移策略,降级策略,延时策略,隔离策略。高可用实际应用方案多种多样,但一般都在实施上述策略,从而构建一个稳定的高可用工程系统。
5.1 冗余 + 自动故障转移策略
最基本的冗余策略就是主从模式。原理是准备两台机器,部署了同一份代码,在功能层面是相同的,都可以对外提供相同的服务。
一台机器启动提供服务,这就是主服务器。另一台机器启动在一旁待命,不提供服务,随时监听主服务器的状态,这就是从服务器。当发现主服务器出现故障时,从服务器立刻替换主服务器,继续为用户提供服务。自动故障转移策略是指当主系统发生异常时,应该可以自动探测到异常,并自动切换为备用系统。不应该只依靠人工去切换成,否则故障处理时间会显著增加。
5.2 降级策略
所谓降级策略,就是当系统遇到无法承受的压力时,选择暂时关闭一些非关键的功能,或者延时提供一些功能,把此刻所有的资源都提供给现在最关键的服务。
在秒杀场景中,下订单就是最核心最关键的功能。
当系统压力将要到达临界值时,可以暂时先关闭一些非核心功能如查询功能。
当秒杀活动结束后,再将暂时关闭的功能开启。这样既保证了秒杀活动的顺利进行,也保护了系统没有崩溃。
还有一种降级策略,当系统依赖的下游服务出现错误,甚至已经完全不可用了,那么此时就不能再调用这个下游服务了,否则可能导致雪崩。所以直接返回兜底方案,把下游服务直接降级。
5.3 延时策略
用户下订单成功后就需要进行支付。
假设秒杀系统下订单每秒访问量是 3000,我们来思考一个问题,有没有必要将每秒 3000 次访问量的压力传递给支付服务器?
答案是没有必要。
因为用户秒杀成功后可以稍晚付款,比如可以跳转到一个支付页面,提示用户只要在 10 分钟内支付完成即可。
这样每秒 3000 次的访问量就被分摊至几分钟,有效保护了系统。技术架构还可以使用消息队列做一个缓冲,让支付服务按照自己的能力去处理业务。
5.4 隔离策略
物理隔离:应用分别部署在不同物理机、不同机房,资源不会互相影响。
线程隔离:不同的请求进行分类,交给不同线程池处理,当一类请求出现高耗时和异常,不影响另一类请求访问。
6 无所不备则无所不寡
《孙子兵法》虚实篇告诉我们一个道理:备前则后寡,备后则前寡,备左则右寡,备右则左寡,无所不备,则无所不寡。
力量集中在前,后面就空虚。力量集中在后,前面就空虚。力量集中在左,右面就空虚。力量集中在右,左面就空虚。如果力量分散在前后左右,那么前后左右就都空虚。
不确定性分散在前后左右无法预测。我们不可能将精力分散在前后左右,但是技术人员至少可以做好一点:保护好系统。
评论