为什么基础服务不应该高可用

2019 年 12 月 02 日

为什么基础服务不应该高可用

为什么这么设计(Why’s THE Design)是一系列关于计算机领域中程序设计决策的文章,我们在这个系列的每一篇文章中都会提出一个具体的问题并从不同的角度讨论这种设计的优缺点、对具体实现造成的影响。如果你有想要了解的问题,可以在文章下面留言。


作者在去年使用过 Google Cloud 平台提供的 Kubernetes 来管理生产环境的集群,然而在托管的过程中却经历了一些比较严重的线上事故,几个集群的中的节点因为停机维护而同时重启导致线上的服务几个小时都处于不不可用的状态。


当然事故时间如此之长的原因有很多,在这里不会展开讨论,然而事故刚刚出现时作者曾经也想去责怪和质疑谷歌云服务的稳定性,但是在随后的分析中得出了另一个结论『你的基础服务其实不应该高可用』,我们在这篇文章就会为各位读者分享作者产生这一观点的原因。


概述


为了帮助大家理解今天的内容,我们需要帮助各位读者理解问题中的两个个关键点,也就是高可用意味着什么、基础服务在这里的定义以及基础服务和 SLA 之前的关系。



高可用


想要让服务达到高可用并不是一个容易的事情,不仅服务运行过程中出现的事故会影响可用时间,用于维护的计划停机和更新其实也会影响服务整体的可用时间,如果一个服务要求可用性为 99.95%,那么全年不工作的时间可能只有 4.38 小时,每个月只能宕机 21.9 分钟。


可用性不可用时间(每年)不可用时间(每月)
99%87.6h7.3h
99.9%8.76h0.73h
99.99%52.56min4.38min
99.999%5.26min26.3s
99.9999%31.56s2.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% 了,这也就是服务高可用的唯一解决方案。


总结


我们在这篇文章中分析了『为什么基础服务不应该高可用』这一问题,这一个乍听起来没什么道理的观点还是非常值得我们去深入思考和探索的,简单总结一下,基础服务不需要保证高可用的几个原因:


  1. 在足够长的时间中,任何服务都没法保证 100% 可用,100% 可用更像是一个危险的承诺,一旦默认了这个假设就不利于我们构建高可用的服务;

  2. 边际成本是提升可用性时必须要考虑的因素,作为服务提供商必须要衡量提升可用性的成本和收益,而过高或者过低的可用性都会降低总体的收益;

  3. 服务的高可用从来都不来源于单一的依赖,只有使用更多异构的副本和组件才能尽可能保证服务的稳定;


今天的讨论的问题其实并不只是一个技术问题,我们在做设计时也不应该仅仅考虑技术因素,很多的权衡与设计都来源于技术之外的其他因素。


这篇文章也不是为基础服务保证低可用提供理由,基础服务的价值就在于提供稳定的服务,作者更想让各位读者思考这一问题背后的非技术因素。


到最后,我们还是来看一些比较开放的相关问题,有兴趣的读者可以仔细思考一下下面的问题:


  • 如果可用性高于约定的 SLA,很多服务提供商会在一个可用性计算周期结束之前故意动触发服务的宕机,你觉得这种做法背后的原因是什么?


如果对文章中的内容有疑问或者想要了解更多软件工程上一些设计决策背后的原因,可以在博客下面留言,作者会及时回复本文相关的疑问并选择其中合适的主题作为后续的内容。


Reference



相关文章



关于图片和转载


本作品采用知识共享署名 4.0 国际许可协议进行许可。


  转载时请注明原文链接,图片在使用时请保留图片中的全部内容,可适当缩放并在引用处附上图片所在的文章链接,图片使用 Sketch 进行绘制,你可以在 [](https://draveness.me/draveness.me/sketch-sketch) 一文中找到画图的方法和素材。
复制代码


微信公众号


关于评论和留言


  如果对本文 [](https://draveness.me/whys-the-design-unstable-infrastructure) 的内容有疑问,请在下面的评论系统中留言,谢谢。
复制代码


本文转载自Draveness · GitHub技术博客。


原文链接:https://draveness.me/whys-the-design-unstable-infrastructure。


2019 年 12 月 02 日 13:29147

评论

发布
暂无评论
发现更多内容

原创 | 使用JUnit、AssertJ和Mockito编写单元测试和实践TDD (十五)编写测试-断言\假设\使测试失效

编程道与术

Java 编程 TDD 单元测试 JUnit

霸榜18年,作者连续20年获得微软MVP,这本SQL书凭什么成为畅销经典

图灵社区

数据库 SQL语法 sql查询

谈谈控制感(13):为什么是旁观者清?

史方远

读书笔记 个人成长 心理学 随笔杂谈

redis持久化RDB与AOF

wjchenge

redis

【vue-openlayers】弹窗

学习委员

html Vue 前端 openlayers ol

路漫漫其修远兮

无心水

LeetCode | 1. Two Sum 两数之和

Puran

Python C# 算法 LeetCode arts

收藏!如何有效实施devops?

DevOps 运维 持续集成 开发 自动化测试

原创 | 使用JUnit、AssertJ和Mockito编写单元测试和实践TDD (十四)编写测试-显示名

编程道与术

Java 编程 TDD 单元测试 JUnit

Docker 搭建 Postgres + pgAdmin 环境

姜雨生

Docker DevOps postgres

【译】业务转型是什么?

涛哥

业务中台 数字化转型

一文入门JVM虚拟机

Simon郎

深入理解JVM

同一浏览器只允许登录一个账号

brave heart

Vue 前端

洞悉MySQL底层架构:游走在缓冲与磁盘之间

arthinking

MySQL 数据库 MVCC

坚持ARTS-week2

王钰淇

ARTS 打卡计划

面试题:教你如何吃透RocketMQ

奈学教育

架构 RocketMQ 架构设计

安全做到首位 统信UOS后激勃发

统小信uos

网络安全 操作系统

Vim使用总结

JDoe

vim

SpringBatch系列入门之Tasklet

稻草鸟人

spring SpringBatch 批处理

ARTS打卡week#1

对方正在输入…

ARTS 打卡计划

分布式事务 - 理论模型

Java收录阁

分布式事务

程序员的晚餐 | 6 月 2 日 红烧鸡爪的味道

清远

美食

手机是21世纪最成功的毒品

Neco.W

学习 提升效率 工作

我们是活着,而不是活过

小天同学

个人感想 生活,随想 随笔杂谈 日常思考

美国黑客曝出政府惊天内幕,看区块链如何解决!

CECBC区块链专委会

CECBC 区块链技术 民生 不可篡改 信息公开

初识 LeetCode

Puran

LeetCode arts

运维日志里隐藏的安全危机,你知道怎么挖吗?听听专家怎么说

secisland

态势感知 关联分析 SOC

架构演变之路:为何要搞微服务架构?

arthinking

Kubernetes 微服务 dubbo SpringCloud

『PyTorch』使用指定GPU的方法

kraken0

人工智能 学习 图像识别

奈学大数据开发工程师分享787个技术,快来收割

奈学教育

大数据

Hive底层执行引擎的深度剖析(免费)

奈学教育

大数据 hive

为什么基础服务不应该高可用-InfoQ