SRE读书笔记
2022-09-22
11分钟阅读时长
SRE相关的书籍,截止目前google出了2本,分别是2016年的的《Site Reliability Engineering: How Google Runs Production Systems》和2020年的《The Site Reliability Workbook》。这两本书是互补关系,需要先阅读第一本,然后再看第二本。
第一本网上有免费的电子书,或者看中文也有扫描pdf。
概述
-
SRE团队必须将50%的精力花在真实的开发工作上;
-
SRE团队的主要职责包括:
- 可用性改进;
- 延迟优化;
- 性能优化;
- 效率优化;
- 变更管理;
- 监控;
- 紧急事务处理;
- 容量规划与管理;
-
SRE处理运维工作的一项准则是:在每8~12小时的on-call轮值期间最多只处理两个紧急事件;
-
产品事故的事后总结包括:
- 事故发生、发现、解决的全过程;
- 事故的根本原因;
- 预防或者优化的解决方案;
-
SRE的目标不是0事故运行,而是有一定的错误预算。大部分服务不应该追求100%的可靠性;
-
监控系统应该只包含三类输出:
- 紧急警报
- 工单
- 日志
-
事故平均恢复时间(MTTR)和平均失败时间(MTTF)是可靠性最重要的指标;
-
应当尽可能自动化地恢复事故,并将相关经验记录在运维手册上,后者是SRE团队重点维护的文档;
-
70%的生产事故是由某种部署的变更而触发,变更管理的最佳实践:
- 渐进式发布(灰度);
- 迅速而准确地检测到问题的发生;
- 当出现问题时,安全迅速地回退改动;
-
需求预测和容量规划是对未来服务稳定性的预期,应当:
- 有一个准确的自然增长需求预测模型,需求预测的时间应当超过资源获取的时间;
- 应当有准确的非自然增长的需求来源的统计;
- 周期性压力测试,以便准确地将系统原始资源信息与业务容量对应起来;
-
高效地利用系统资源,简单来说就是在延迟目标允许范围内,通过合理配置,最大化提高系统资源利用率;
Google基础设施
- 一般应建立N+2个服务实例,保证流量峰值满足需求;
- 如果业务的生命周期尚未达到成熟/稳定运行阶段,应当执行更低的可用性目标;
- 如果服务允许停机,那么计划内停机时间应该计算在SLO中;
- 可用性是最基本的目标,其他业务指标需要根据业务特性来指定。如最大延迟时间等;
- 基础设施组件由于需要服务多个用户,用户之间的需求可能恰好相反:
- 比较明确的解决方案是将服务做的尽可能好,不过这可能导致服务成本激增;
- 另一个方案是将基础设施分割成多个服务,在多个独立的服务水平上提供该服务;
- 通过SLO预算来管理版本发布的速度,可以有效降低频繁发布造成的风险;
服务质量目标
-
几个术语:
- SLI,服务质量指标,可以量化的基础指标;如请求延迟、错误率、吞吐量等;
- SLO,服务质量目标,基础指标的预期值;
- SLA,服务质量协议,当基础指标不符合预期时的应对计划;
-
SLI需要按着用户对于服务的期许来制订,常用指标包括:
- 用户可见的服务系统:可用性、延迟以及吞吐量;
- 存储系统:延迟、可用性和数据持久性;
- 大数据系统:吞吐量和端到端延迟;
-
指标的收集,一般利用某种监控系统+日志分析系统完成,有时候还要结合客户端数据的收集;
-
SLO制定标准:
- 大部分SLI指标应该以分布,而非平均值来定义。平均值会掩盖长尾延迟和其中的变化;
- 一般使用百分位指标来分析指标的分布,一般SRE更关注高百分位的长尾数值;
- 需要明确SLI汇总的间隔、汇总的范围和度量频率;
- SLO应该尽量简单、少量,基于系统长期运行目标来指定;
- 对外SLO可以比内部SLO更低,以留下处理的余量;
- 实际SLI不要过度超出SLO,可以使用主观可控模式减少过渡依赖;例如延迟类SLI可以通过手动增加延迟、限速的方式避免性能过快;
减少琐事
- 这里的琐事指的是可自动化的、重复的、随着服务规模线性增长的非预期工作,一般此类工作没有持久价值;
- 如前所述,SRE需要保留至少50%的时间用于开发;
分布式系统监控
- 监控系统主要解决两个问题:什么东西出故障了;为什么会出故障;
- 黑盒监控是面向对象的,代表了目前正在发生的问题;白盒监控则通过对系统内部信息的分析,检测到即将发生的问题,或者业务系统由于重试导致的无法发现的问题;
- 用户可见系统最重要的4个黄金指标:
- 延迟。需要区分成功和失败请求的延迟;
- 流量。即吞吐量,HTTP服务器一般是QPS,音视频系统则使用网络IO速率或者并发会话数量来表示;
- 错误。捕获所有失败的请求;
- 饱和度。一般指某种资源的占用率,如内存、cpu、硬盘容量和i/o等;
- 监控频率与SLO的值密切相关,应当避免过渡频繁的检查;
- 应当尽量避免告警的误报,需要谨慎设定报警的条件;
- 需要区分系统的必要复杂度和意外复杂度;
- 定期精简无用代码,增加代码膨胀检测;
- 一般黑盒测试基于探针技术;白盒测试基于时序数据收集技术;
- 系统最近的变更(上线、配置更改),一般与灾害的关联极大,需要相关日志记录;
- 过于自动化的方案,有时候会做出过激的应对措施,以及自动化系统本身造成的bug可能是灾难性的;
on-call
- 对同一起事故,应当避免多次告警,合理的进行告警分组非常重要;
- 低优先级告警应当尽量避免触发,告警策略需要和SLO目标一致;
- 研发团队需要配合SRE团队on-call;
- 需要保证一定的on-call强度,避免自信心问题;
- 需要周期性的灾害演练;
- 回滚也需要测试:并不是所有的回滚都会生效;
- don’t panic. 大型问题优先需要做的永远是恢复系统,但尽量保留事故现场。
应急处理流程
-
角色分配:
- 总控:负责组建事故处理团队,掌握事故的概要信息。与其他部门协调工作,对外联系;
- 事故处理团队:应当有一个负责人,事故中唯一有权修改系统的团队;
- 发言人:向相关人员发送事故相关通知,维护事故文档;
- 后勤:填写bug报告记录系统,安排职责交接记录;
-
最佳实践:
- 划分优先级;
- 事前准备;
- 信任;
- 反思;
- 考虑替代方案;
- 练习;
- 换位思考;
事后总结
- 事后总结的目的确保实施有效的措施使得未来重现的几率和影响降低;
- 并非所有的事故都需要事后总结,基本条件包括:
- 用户可见的宕机时间,或者服务质量降低达到一定程度;
- 任何类型的数据丢失;
- on-call工程师需要人工介入的事故(包括回滚、切换用户流量等);
- 问题解决耗时超过一定限制;
- 监控问题,即由人工发现的问题,而不是报警系统;
- 收到事故影响的部门要求事后总结的场景;
- 对事不对人,客观分析;
- 事后总结适宜使用在线文档协作系统,至少包括以下功能:
- 实时协作
- 开放的评论系统
- 邮件通知
- 事后总结还包括正式的评审和发布过程,评审条件包括:
- 关键的灾难数据是否已经被收集并保存起来了?
- 本次事故的影响评估是否完整?
- 造成事故的根源问题是否足够深入?
- 文档中记录的任务优先级是否合理,能否及时解决根源问题?
- 这次事故处理过程是否共享给了所有相关部门?
- 应当鼓励甚至奖励事后总结做得好的SRE团队人员;
- 除了线上事故之外,其他任何严重问题都可以有事后总结,如公关危机或者产品吐槽过多;
故障跟踪
- 尝试聚合同一个故障引起的所有告警;
- 为告警信息加标签;
- 分析历史故障,统计类似故障(根据标签);
- 允许手动创建告警;
应对过载
- 运维一个可靠系统的一个根本需求,就是能够优雅处理过载;
- 按着QPS来规划服务容量,或者是按着其他静态属性来估算,一般是错误的选择;
- 更好的选择是直接以可用资源来衡量可用容量。大部分情况下,用CPU数量做资源配给的主要信号就足够了;
- 高频请求的客户端应当根据回复实现自适应节流算法;
- 需要划分服务/请求的优先级,保证重要请求得到回复;
- 过载的一般处理方式是进行服务降级;
- 过载会导致的可能问题:
- 资源耗尽:CPU、内存、文件描述符
- 队列过长
- RPC超时
- CPU缓存效率下降
- OOM
- 优雅降级:返回计算量更小、返回速度更快的、不那么精确的结果;由于很少使用,所以需要谨慎测试保证覆盖率;
- 重试:
- 一定要使用随机化的,指数型递增的重试周期;
- 考虑使用一个全局重试预算;
- 避免在多个层级重试导致的乘数效应;
- 使用明确的返回代码,而不是所有的错误都重试;
- 某些错误应当快速失败,而不是重试;
- 超时:
- 所有请求都应当设置一个恰当的超时时间;太长会导致工作线程耗尽,太短会导致重型请求总是失败;
- 服务端应该在请求处理的各个阶段判断是否已经超过客户端超时时间,避免浪费资源做无用功;
- 可以在入口层加上请求的绝对截止时间戳,这样请求在多个微服务间传递时,可以及时截断请求
- 确定性的长时间响应,应当尽量异步化;
- 缓存:
- 区分延迟性缓存和容量型缓存,后者需要良好的可恢复设计;
- 使用热缓存的系统,流量应该缓慢增加,等到缓存预热之后再逐步增大请求量;
- 压力测试应当考虑到缓存的影响,测试逐渐升高和压力陡增两种流量场景;
- 服务间相互通信,环形通信可能导致分布式死锁,应当尽量避免;
- 压力测试直到服务崩溃,并保证服务崩溃的情况下,不影响成功请求的速率;
- 反向压测:逐步降低负载,看服务能不能自行恢复稳定,记录下相关数值;
- 尽量使用最常用的客户端来做测试,而不是模拟的客户端;
- 非关键性后端停止服务应当不影响主要功能的使用;
- 如果一半的服务由于正在初始化还不能正常工作,另一半的服务由于过载无法正常工作,此时需要暂停健康检查功能;
- 健康检查分为进程级别和服务级别两种,一般集群管理系统使用前者,负载均衡器使用后者;
- 非流量型负载(如后端定时任务)可以在过载期间暂时关闭;
分布式共识
- BASE:基本可用(basically avaiable),软状态(soft state)和最终一致性(eventual consistency);
- 大多数支持BASE语义的系统都依赖多主复制机制,将写操作分布在多个进程中,然后通过复制达到最终一致性;
- 分布式共识算法的几个概念:
- 分为崩溃不可恢复和崩溃可恢复两种,后者当然更有用;
- 拜占庭式问题:某个进程由于某种原因发送错误消息的可能性;
- 在不稳定的网络条件下,不存在任何一种分布式共识算法可以保证共识可达到;
- 实践中,足够多的副本和良好的网络连接状态可以在大多数条件下保证共识可达;
- 重试的连锁反应通过指数退避来规避;
- 非拜占庭情况下,2f+1个副本组成的共识组可以同时承受f个副本失败而继续运行;
- 拜占庭情况下,则需要3f+1个副本;
- 生产系统中,分布式日志是分布式共识系统中最重要的一部分;
- 故障域:同时出问题的物理范围;
- 向一个采取“大多数”法定仲裁过程系统中增加新的副本可能会降低系统的可用性;5个需要3个,6个需要4个,可用性从3/5下降到2/3;
- 对共识系统本身也需要监控,频繁的变动leader,副本的lag程度等指标都需要考虑;
分布式调度系统
- 对于分布式调度系统而言,一般倾向于在最差情况下跳过某些任务,而不是去冒执行两次的风险;
- 一个简单的分布式调度系统可以使用一主多从架构,使用paxos算法选举leader,后者是真正运行cron的进程实体;
- 避免同一时间点的惊群问题;
- 如果周期性的任务需要不断更新结果,此时使用cron方式调度并不合适,更好的方法是使用一个持续运行的流水线;
数据完整性
- 各团队需要为不同的失败场景定义一系列数据可用性SLO;
- 各团队需要定期进行演练,以确保他们有能力满足这些SLO;
- 事故类型:
- 根源问题:用户行为、管理员的错误、应用程序bug、基础设置bug、硬件故障以及部署事故;
- 影响范围:大规模,还是一部分特定的数据;
- 发生速度:一瞬间,还是缓慢持续的;
- 有效的数据恢复计划必须覆盖上述所有因子的组合;
- 最常见的用户可见的数据丢失问题,是由于数据删除和软件bug引起的引用完整性(外键)问题;
- 将全部相关数据恢复到某个时间点几乎是不可能的,因为这要求备份在一瞬间完成;
- 备份的分级多样性是关键,无论如何,热备无法替代冷备,冷备也无法防止磁盘被破坏;备份是为了恢复;
- 最常用的策略:软删除。值得注意的是,软删除的数据应该在一段时间之后真正的物理删除,而不能一直留在系统里;建议至少保留2个月;
- 全量备份的成本和压力都比较大,因此比较常见的方案是在非峰值时段使用全量备份,繁忙时段进行增量备份;
- 持续性对数据恢复流程进行测试,如果恢复无法完成则发出警报;
产品发布
- 专门的发布团队,称作发布协调工程师(LCE)团队;
- checkList的必要性,主要是用在多个部门之间的协调工作;
- 对每个产品,有必要维护一个常用的check question列表,并定期审核和更新;
- 设计评审中需要确定服务正确地使用了已有的通用基础设施,并确保这些基础设施的负责人加入到发布流程中;
- 需要进行容量规划的评审,首次发布一般有一个流量峰值,需要尽量考虑冗余度和弹性伸缩;
- 需要进行故障行为的评审,保证系统不存在稳定性问题,以及拥有故障恢复的能力;
- 需要进行安全性评审,包括恶意攻击和非恶意的客户端bug;
- 需要对配置文件的更新进行评审,确定其版本兼容性;
- 需要对外部依赖项进行评审;
最佳实践
以下摘自SRE workbook,即第二本SRE书籍。
- 日志总是能比metric生成更详细的报告,基于日志来做报表,而不是Metric;
- 基于Metric做告警,将日志分析导出成Metric;
- 将配置看做代码,推荐使用jsonnet这种生成配置的封闭型语言,而不是直接用json/yaml,或者js/python这种脚本当做配置;
- 要检查配置,防止配置错误导致的应用崩溃;
- 服务的SLO与其依赖服务的SLO正相关;
- 告警设定考量:
- 精确率:在所有检测到的事件中,确实是重大事件的比例是多少。告警在低流量时段可能会对非重大事件特别敏感;
- 查全率:在所有客观存在的重大事件中,被告警系统检测到的比例;
- 检测用时:发出告警通知距离事故发生的延迟时间;
- 重置用时:在问题得到解决后,告警还会持续多少时间;
- Google推荐使用4周的滚动窗口作为SLO时间窗口;并推荐使用多个时间窗口的SLO燃烧率作为告警阈值;