为什么基础服务不应该高可用
为什么这么设计(Why's THE Design)是一系列关于计算机领域中程序设计决策的文章,我们在这个系列的每一篇文章中都会提出一个具体的问题并从不同的角度讨论这种设计的优缺点、对具体实现造成的影响。如果你有想要了解的问题,可以在文章下面留言。
作者在去年使用过 Google Cloud 平台提供的 Kubernetes 来管理生产环境的集群,然而在托管的过程中却经历了一些比较严重的线上事故,几个集群的中的节点因为停机维护而同时重启导致线上的服务几个小时都处于不不可用的状态。
当然事故时间如此之长的原因有很多,在这里不会展开讨论,然而事故刚刚出现时作者曾经也想去责怪和质疑谷歌云服务的稳定性,但是在随后的分析中得出了另一个结论『你的基础服务其实不应该高可用』,我们在这篇文章就会为各位读者分享作者产生这一观点的原因。
概述
为了帮助大家理解今天的内容,我们需要帮助各位读者理解问题中的两个个关键点,也就是高可用意味着什么、基础服务在这里的定义以及基础服务和 SLA 之前的关系。
高可用
想要让服务达到高可用并不是一个容易的事情,不仅服务运行过程中出现的事故会影响可用时间,用于维护的计划停机和更新其实也会影响服务整体的可用时间,如果一个服务要求可用性为 99.95%,那么全年不工作的时间可能只有 4.38 小时,每个月只能宕机 21.9 分钟。
可用性 | 不可用时间(每年) | 不可用时间(每月) |
---|---|---|
99% | 87.6h | 7.3h |
99.9% | 8.76h | 0.73h |
99.99% | 52.56min | 4.38min |
99.999% | 5.26min | 26.3s |
99.9999% | 31.56s | 2.63s |
假设我们需要达到 4 个 9 的可用性(99.99%),全年的不可用时间只有不足 1 小时,每个月的不可用时间只有 4.38 分钟,99.99% 就是 Google 云计算引擎对外提供的服务质量,每个月不可用时间小于 5 分钟,这也是作者见到过云服务商对外提供的最高服务等级协议(Service-Level Agreement, SLA)了。
很多人可能认为每个月不可用 5 分钟也没什么难的,但是如果你的业务服务建立在稳定性只有 99.95% 甚至 99.9% 的服务上时,你还能保证服务的高可用么?
基础服务
在这篇文章中我们谈到的基础服务指的其实都是基础设施和基础架构,例如用于支撑整个业务系统的 MySQL、Redis 以及 Kubernetes 等系统,这些系统的稳定性和可用性会影响整个业务系统的可用,由于这些基础服务往往提供了相对较为简单和稳定的功能,所以我们对基础服务的可用性有着更高的要求。
业务服务由于经常发版和迭代,有时很难保证服务的稳定和可用,而基础服务和基础架构因为处于更加底层的位置,所以它们稳定性的提升对于依赖它们的上游来讲会有比较大的收益,这也是所有业务同学对基础服务以及架构的期望 —— 保证尽可能高的可用性并保证服务不会宕机。
关系
虽然说所有的开发者都希望基础服务能够提供尽可能高的可用性和 SLA,但是极高的 SLA 对于整体业务的长期稳定并不是一件好的事情,可能在短期内能够提供较大的价值,但是从长远来看可能会造成更大的破坏,这也就是今天想要分析的问题 —— 『为什么基础服务不应该高可用』。
设计
在这一节中,我们将从以下的三个方面依次分析『为什么基础服务不应该高可用』:
凡是可能出错的事情就一定会出错;
成本因素有时是技术决策的最关键因素;
只有使用更多异构的副本才能保证更高的可用性;
最后一点并不是这个观点的强论点,我们放在这里只是为了让各位读者了解能够保证服务高可用的唯一方法,需要注意的是通过保证代码逻辑的正确、服务的正确配置来提升可用性并不是我们在这里要讨论的内容,这是一个服务正常工作的前提。
墨菲定律
墨菲定律其实已经是一个几乎所有地球人都知道的定律了,它在大多数的时候都会被解释成『凡是可能出错的事情就一定会出错』,任何一个线上的服务能够正常运行都是极其偶然的,只要时间拉的足够长,我们就没有办法保证任何服务 100% 的可用性。每一个服务的正常工作可能都需要满足以下的条件:
依赖的所有基础服务能够正常工作;
依赖的所有组件能够正常工作;
服务的所有配置都非常合理且无一错误;
能够通过网线连接到互联网并接收来自其他客户的请求;
能够有充足的电力保证硬件的正常工作;
磁盘不会突然损坏或者空间不足;
不会有虫子爬到机箱里阻断电源;
不会受到核弹、极端自然灾害的威胁和影响;
...
在这样不稳定的世界中运行一个稳定的服务是非常困难的,而想要在尽可能长的时间中保证服务的 100% 可用是不可能做到的,一旦我们接受了所有依赖条件都 100% 可用这个设定,那么当灾难真正发生时,我们是无法做到及时恢复和容灾的。
从这一点来看,基础服务其实也是没有办法做到 100% 可用,它只能尽其所能提高可用性,无法做到在足够长的时间中绝对可用。
成本因素
很多人可能都会认为服务的可用性一定是越高越好,然而并不是这样的,成本因素在很多情况下限制了服务提供的可用性,经济学原理告诉我们『理性人思考边际成本』,对于是否应该提高可用性,我们应该思考继续提高可用性带来的收益与损失。
服务的可用性最后还是一个收益与成本的权衡问题,也就是继续提升可用性的边际成本是否大于造成事故或者可用性不达标时的赔偿和损失。
随着可用性的不断提升,提高可用性的边际成本会以指数的量级升高,而服务宕机造成的损失也会随着服务的可用性的提高急速下降,这两个不同曲线的交点就意味着两者成本相当,这时再提升服务的可用性就没法带来经济上的利益了,需要注意的是这里的曲线画的相对比较简单,只是帮助读者理解高可用性与成本之间的联系。
我们其实可以这样理解这个问题,服务提供商提供的服务是为了获得有形和无形的资产,服务商对外宣称的『高可用』其实只是宣传的一种手段,很多时候高可用并不是服务方主要考虑的因素,真正促使它提供高可用服务的还是背后的直接经济利益和造成事故时需要赔偿的名誉和金钱损失。
服务可用性的提升从 2 个 9 提升到 3 个 9 并不是一件特别困难的事情,但是从 4 个 9 提升到 5 个 9 就需要考虑非常多的容灾措施,可用性每提升 1 个 9 都需要研发人员付出指数倍的努力,这其实也就是大多数的服务商最多只提供 99.99% 或者 99.95% 可用性的原因,因为在这个可用性下,服务提供商的利益才能最大化。
异构服务
上述的两个原因已经能够很好地回答今天的问题了,但是作者还是想通过最后这一小节简单介绍如何才能使用『较低可用性』的基础服务构建高可用的服务,想要让单一服务或者组件的可用性不成为系统可用性的瓶颈,我们只能依赖异构的服务或者组件,这里的异构其实是说提供相同的功能,但是有着一个或者多个不同的属性,例如:
物理机不同:部署在不同机器上的 Redis 服务;
协议和代码不同:本地部署的 Redis 和 memcached 服务;
服务提供商不同:谷歌云和 AWS 的 Redis 服务;
地理位置不同:北京和上海的机房中的 Redis 服务;
...
假如我们只依赖于 1 个可用性为 99.9% 的 Redis 服务,那么我们服务的可用性最高只有 99.9%,但是如果我们依赖两个可以相互替代的服务,例如:Redis 和 memcached,那么我们整个系统的可用性的瓶颈就不再是 99.9% 了,这也就是服务高可用的唯一解决方案。
总结
我们在这篇文章中分析了『为什么基础服务不应该高可用』这一问题,这一个乍听起来没什么道理的观点还是非常值得我们去深入思考和探索的,简单总结一下,基础服务不需要保证高可用的几个原因:
在足够长的时间中,任何服务都没法保证 100% 可用,100% 可用更像是一个危险的承诺,一旦默认了这个假设就不利于我们构建高可用的服务;
边际成本是提升可用性时必须要考虑的因素,作为服务提供商必须要衡量提升可用性的成本和收益,而过高或者过低的可用性都会降低总体的收益;
服务的高可用从来都不来源于单一的依赖,只有使用更多异构的副本和组件才能尽可能保证服务的稳定;
今天的讨论的问题其实并不只是一个技术问题,我们在做设计时也不应该仅仅考虑技术因素,很多的权衡与设计都来源于技术之外的其他因素。
这篇文章也不是为基础服务保证低可用提供理由,基础服务的价值就在于提供稳定的服务,作者更想让各位读者思考这一问题背后的非技术因素。
到最后,我们还是来看一些比较开放的相关问题,有兴趣的读者可以仔细思考一下下面的问题:
如果可用性高于约定的 SLA,很多服务提供商会在一个可用性计算周期结束之前故意动触发服务的宕机,你觉得这种做法背后的原因是什么?
如果对文章中的内容有疑问或者想要了解更多软件工程上一些设计决策背后的原因,可以在博客下面留言,作者会及时回复本文相关的疑问并选择其中合适的主题作为后续的内容。
Reference
High availability · Wikipedia
Compute Engine Service Level Agreement
系列文章
002 为什么使用通信来共享内存
长按二维码↑
关注『真没什么逻辑』公众号