如今,随着Cloud Native,SRE,以及DevOps的发展,大规模软件系统的高可用、可扩展、可伸缩、系统管理、高效运维等似乎正在被一个新的词汇所代替,那就是:可靠性工程。
本文是Google SRE Ramón Medrano Llamas 在西班牙奥维耶多大学希洪校区理工学院关于可靠性工程设计的分享。
原文分享的标题是:《Designing and Operating Highly Available Software Systems at Scale》,即《大规模高可用软件系统的设计与运维》。
原文内容分为六部分:
第一部分:什么是Site Reliability Engineering(SRE)?
第二部分:SRE的一天是如何度过的?
第三部分:为大规模而设计
第四部分:大规模Web应用程序的剖析
第五部分:为故障而设计
第六部分:运维注意事项
首先是免责声明,我把这个内容调整在第一页,一为引起注意,二是说明作者的分享意图:把工作中遇到的具体问题抽象为一般问题来描述。
免责声明:
- 下面的图片都没有描述谷歌实际的服务或技术,但它们反映了谷歌服务运行的规模,以及运行这些服务所需的技术。
- 下面的图片中描述的所有问题都是运行谷歌服务需要解决的问题,它们都属于谷歌SRE组织的范畴。
第一部分:什么是(Site Reliability Engineering,SRE)?
有人说SRE是软件工程师和系统管理的一种结合,是DevOps工程师的另外一种称呼。
Google对SRE的定义是:
- 我们是谁:肩负独特使命的软件工程师……
- 我们做什么:让谷歌提供持续不间断的服务。
- 我们如何做:结合主动(proactive)工程和被动(reactive)工程,使谷歌全球规模的系统工作的更好。
- 为什么这么做:用户期望谷歌-总是可用的、快速响应、正确运行。
SRE的主动工程:
- 设计
- 规划
- 自动化
- 咨询和发布
- 容灾测试
SRE的被动工程:
- 监控
- 调试及故障排除
- 问题根源分析
- 性能调优
第二部分:SRE的一天是如何度过的?
“典型”的一天。
检查代码、更改和设计文档。
阅读电子邮件。加入视频会议。
头脑风暴。分析。设计。写代码。
在每日站会中与团队见面。
查看技术讨论。提出问题。
盯着系统仪表盘。
写路线图和计划。
闲谈,聊天。吃东西。玩。开怀大笑。
进入状态。
“有趣”的一天。
对整个服务随时待命。
又是安静的一天?开始在项目上工作。
突然发现问题:系统的一部分出了故障。
初步检查:有多少用户受到影响?
想办法减轻故障以恢复服务。
深度调查:找出根本原因。
分析最新的变化和日志。
发现潜在的罪魁祸首。
回滚变更。
事后复盘。
又进入安静状态。
第三部分:为大规模而设计
服务所有查询请求
- 面对逆境:尽管我们应该尝试服务所有查询请求,但我们不能一个不漏的服务每一个查询请求,而是只服务99.XXX%的查询请求。
- 可靠性成本:随着服务可用性数字9的增加,可靠性成本呈指数级增长。
- 可能出现的故障:内存、CPU、硬盘、网卡、电源、电缆、挖断光纤的挖掘机、撞向变电站的卡车…
缩放的艺术
假设你编写一个Web应用程序,
让它在一个服务器上运行,
后面接一个数据库,
然后把浏览器指向它,
这意味着所有都结束了,对吧?
一个简单的服务,如下图所示:
现在,需要改变什么:
假设你的Web应用程序必须为全世界一亿用户提供服务。
一亿用户意味着什么?
一亿用户意味着什么?
每天100亿的请求
一亿用户意味着什么?
平均每秒10万的请求
一亿用户意味着什么?
高峰每秒20万的请求
一亿用户意味着什么?
高峰每秒200万磁盘寻址(IOPS)
我们需要哪些资源来服务一亿用户?
- 大量的服务器。
- 还有本文不打算讲的东西。
- 也被称为“仓储级计算”。
即,1亿用户在高峰时需要200万IOPS:2万个磁盘(每个磁盘100 IOPS),834台服务器(每台服务器24个磁盘),486英尺(148米)的服务器堆叠(每台服务器4个机架单元(RU),每个RU 4.44cm厘米)。
第四部分:大规模Web应用程序的剖析
回到一个简单服务的例子:
通过使用复制技术提高可用性和伸缩性:
这样形成网状(mesh)的拓扑结构,下图并未展示所有的连接:
使用抽象思维再次简化,一个方框代表该服务器类型的所有副本:
然后采用分层思维细化为架构图,层次之间的服务器互相通信:
一个架构示例:名字完全是虚构的,这并不反映任何真实的系统,也不反映系统的生命周期。
循环通信?
偶尔,服务器也需要和自己通信。
把这个架构图缩小,作为一个子系统。画图需要更多的空间。
如何部署1000台服务器?
不能发布1000个IP地址(每个服务器一个),添加一个IP负载均衡器来分担服务器上的流量。
然后,多个数据中心之间形成负载均衡网络,下图并没有显示所有的连接。
如何将流量发送到前端负载均衡器?
引入DNS服务器,并感知IP地理位置。
监控
既然已经将流量送到了正确的位置,那么需要知道服务器在做什么。
我们需要监控来弄清楚前端在做什么,它们的负载如何?它们什么时候负载过高?它们要处理多少请求?它们是否提供了我们所期望的功能?
不,我们不会整天盯着屏幕看。这就是自动报警的作用。
服务水平指标
- 服务水平指标(Service Level Indicator,SLI)是对某些属性的服务水平的量化度量。
- 属性是用户关心的维度,例如:
- 延迟:服务已经工作了多长时间
- 可用性:服务工作的频率
- 正确性:服务是否正确的工作
一个服务的服务水平如何量化?
- 一个服务的服务水平有多{快,可靠,可用,...},本质上是一个产品问题
- 对(几乎)所有事情来说,100%的可靠性目标都是错误的:边际改进的成本呈指数级增长
- 总能在某些方面使服务变得更好,但需要在美元、人员、时间和其他优先事项之间进行权衡:产品和研发管理之间最需要处理权衡
服务水平目标
服务水平目标(Service Level Objective,SLO)是一种数学关系:
- SLI≤目标
- 下界≤SLI≤上界。
预算误差:
- SLO与100%的差异。
- 用于风险承担:变更、上线等。
- 预算误差允许更快发布(速度)。
监控架构
- 服务器被深度检测。
- 收集所有数据。
- 如果需要人工操作,则发出报警。
- 可视化可以帮助排除故障。
第五部分:为故障而设计
故障总是会发生。
故障的发生,从低到高的影响:
- 机器
- 交换设备
- 配电单元
- 路由器
- 光纤
- 电力变电站
- 不完美的软件
- 人为错误
- 攻击行为/恶意行为
我们需要为所有这些场景做计划。
使用冗余应对故障
传统方法:如果组件1的中断引起系统故障,则使用组件2,并希望它们不会一起故障。
- 机器:冗余电源、磁盘驱动器(raid)
- 网络:冗余交换机、路由器
- 数据库:两个主机之间冗余的数据库。
缺点是成本高,通常2倍以上的并发症。
了解你的系统——从设计开始,“深入防御”。
故障域:机器
电源单元(Power supply unit,PSU)的 MTBF为100,000小时。对于10,000台机器来说:每10小时有一个PSU故障。
大量的其他故障。
行动:
- 将流量从故障机器切换移开,把故障机器送去修理
- 还可能会将数据转移到其他地方
故障域:(网络)交换设备
症状:连接到一个交换机的数十台机器同时掉线。
行动:
- 把流量从受影响的机器上切换移开
- 关闭交换机。
如果机器存储一些数据,而这些数据的另一个副本在同一个交换机上:恭喜,你刚刚丢失了生产数据。
故障域:电力分配单元
电力分配单元(Power Distribution Unit,PDU)在数据中心内部分配电力。
症状:数据中心的很大一部分突然断电。
可能需要大量的机器,以及必要的网络设备…有时还能产生漂亮的火花。
行动:嗯……非常棘手。
灾难性的断电之后,机器(和硬盘驱动器)可能无法启动。
故障域:数据中心
有些故障模式会破坏整个数据中心:飓风、洪水、地震……
这种情况很少发生,但却是最难处理的。
这意味着仅仅数据存储在一个地区是不够的,所以我们需要数据中心地理分布多样性。
故障域:软件缺陷
这会毁了你的一整天。
行动:
- 犹豫不决时,回滚
- 上线策略应该使这一过程简单而快速
预防:单元测试、集成测试、金丝雀测试、黑箱测试、数据完整性测试
案例研究:恶意软件黑名单宕机
回到数据中心冗余架构
现在我们可以很好地利用DNS的IP地理位置。
数据中心地理分布分布多样性
数据中心地理分布分布多样性
如何应对故障:流量分流
最初是想让服务器有流量,现在是想把流量分离移开!
因为机器/数据中心/区域 都可能发生故障
需要弄清楚什么时候需要分流流量,参见前面关于监控的图片
是否可以使用我们用于将流量分配到机器的相同机制,参见前面关于负载均衡的图片
2个服务器实例的冗余:稳定状态
看起来不错,不是吗?每个服务器只需要处理总负载的50%。
2台服务器实例的冗余:1个服务器故障
任何一台服务器都可能故障,每个服务器都需要能够处理100%的负载,所以我们需要准备预期负载的200%。100%的超额准备是非常昂贵的。
3个服务器实例的冗余:稳定状态
现在,每个服务器只需要处理总负载的33%。
3个服务器实例的冗余:一个服务器故障
在一个服务器故障的情况下,每个剩余的服务器只需要处理总负载的50%。因此,只需要为预期负载的150%提供准备,只需要50%的超额准备(比2个实例的100%的超额准备好得多)。
结论:只要每个服务器的基本成本是边际的,就应该选择大量较小的实例。
第六部分:运维注意事项
变更管理
不允许停机,所有变更都在“飞行中”进行。或者,关闭服务的某一部分。
考虑兼容性。
部署新代码:
- 从小处着手,如果一切顺利,就快速部署大的变更
- 一个一个来:1台机器,1个机架,1个集群,1个区域,1个世界
- 遇到问题就回滚,不要向前合并
- 在全球范围内应用这一原则
灾难恢复
我们已经讨论了故障,现在让我们讨论灾难!
例子:
- 你的一个主要数据中心烧坏了
- 软件bug会在几个月内悄无声息地破坏数据
方案:
“哎呀,我的错”——这句话可能不会奏效
准备应付紧急情况:
- 如何在其他地方提供服务
- 如何取回数据并验证其正确性。
要有“恢复计划”而不是“备份计划”。
机器:是牛群还是宠物?
需要管理运行在10000多台机器上的服务。蓝精灵的数量还不足以命名10000多台机器,即使有,你也无法记住在papasmurf.example.com上运行哪些服务。因此,我们需要一个数据库来告诉我们在哪里运行什么(配置),如果数据库这样说,则需要一个系统使服务X和Y在机器Z上自动化运行。
业务连续性
也被称为“公车因子”:如果某个人被汽车辗过,你还能保证业务连续吗?
新人加入团队,老员工离开。
每个人都需要做出自己的紧急反应。
使系统易于使用和安全,即使不能100%理解它们的输入和输出。
其余部分文档化。
注:公车因子核心概念是管理关键人物流失的风险。比如开发人员可能会休假,离职等。公车因子越大代表关键人物流失导致项目受到影响的概率越小。作者显然把这些因素也作为可靠性工程的考虑范围了。
SRE vs. DevOps vs. Cloud Native
“SRE is a job function, DevOps is a process approach and Cloud Native is an architecture.
SRE是一项工作职能,DevOps是一种流程方法,Cloud Native是一种架构。”