SRE 运维解密 - 服务质量目标:SLI,SLO,SLA
如果不详细了解服务中各种行为的重要程度,并且不去度量这些行为的正确性的话,就无法正确运维这个系统,更不要说可靠地运维了。那么,不管是对外服务,还是内部 API,我们都需要制定一个针对用户的服务质量目标,并且努力去达到这个质量目标。
在这个过程中,我们需要利用一些主观判断结合过去的经验以及对服务的理解来定义一些服务质量指标(SLI)、服务质量目标(SLO),以及服务质量协议(SLA)。这三项分别是指该服务最重要的一些基础指标、这些指标的预期值,以及当指标不符合预期时的应对计划。事先选择好合适的指标有助于在故障发生时帮助 SRE 进行更好地决策,同时也为 SRE 团队判断系统是否正常工作提供帮助。
本文描述了 SRE 团队在指标建模、指标选择,以及指标分析上采用的基本框架。
一、服务质量术语
指标(SLI)
SLI 是指服务质量指标(indicator)——该服务的某项服务质量的一个具体量化指标。
常用的 SLI
大部分服务都将请求延迟——处理请求所消耗的时间——作为一个关键 SLI。其他常见的 SLI 包括错误率(请求处理失败的百分比)、系统吞吐量(每秒请求数量)等。这些度量通常是汇总过的:在某一个度量时间范围内将原始数据收集起来,计算速率、平均值、百分比等汇总数据。
理想情况下,SLI 应该直接度量某一个具体的服务质量。但是很多时候,直接度量信息可能非常难以获取,或者无法观测,我们只能用某种指标来替代。例如,客户端的延迟数据经常是最直接的用户指标,但是由于条件限制可能只能监控服务器端的延迟数据。
可用性(availability)是另外一个 SRE 重视的 SLI,代表服务可用时间的百分比。该指标通常利用“格式正确的请求处理成功的比例”来定义,有时也称为服务产出(yield)。
对数据存储系统来说,持久性(durability)——数据能够完整保存的时间——也是一个重要指标。
虽然 100%的“可用性”是不可能实现的,但是接近 100%的可用性指标是可以实现的一个目标。运维行业经常用 9 的数量来描述可用程度。例如,99%可用性被称为“2 个 9”,99.999%被称为“5 个 9”。目前 Google 云计算服务公开的可用性指标是“3.5 个 9”—— 99.95%可用。
目标(SLO)
SLO 是服务质量目标(Objective):服务的某个 SLI 的目标值,或者目标范围。
SLO 的定义是 SLI≤目标值,或者范围下限≤SLI≤范围上限。例如,对莎士比亚服务来说,返回结果的速度应该是很“快”的,那么我们可以定义一个 SLO,要求搜索请求的平均延迟小于 100ms。
选择适合的 SLO 是一个非常复杂的过程
选择一个合适的 SLO 是非常复杂的过程。第一个困难点是很有可能无法确定一个具体的值。例如对外部传入的 HTTP 请求来说,每秒查询数量(QPS)指标是由用户决定的,我们并不能针对这个指标设置一个 SLO。
但是,我们可以做的是指定平均请求延迟小于 100ms,确立这个目标可以鼓励开发者优化前端服务降低延迟,或者采购某种延迟更低的硬件。(100ms 在这里只是一个随意选择的值,但是一般来说速度快要比速度慢更好,因为用户可见的延迟超过一定数量后会使得参与程度下降。详情参见“Speed Matter”,文献[Bru09]中有详细介绍)。
而且,可能不那么直观的是,这两个 SLI——QPS 和延迟——很可能是相关的:QPS 升高通常会导致延迟升高,服务到达一定负载水平后性能下降是很常见的。
SLO 的选择和公布非常重要
SLO 的选择和公布可以帮助设立用户对服务质量的预期。该策略可以应对那些没有根据的抱怨—“服务太慢了”。如果没有一个明确的 SLO,用户经常会按照自己的理解设置一个服务性能的预期,即使这可能跟运维人员或者设计者所想的完全不同。
这种问题可能会导致:
对某个服务的过度依赖—用户错误地认为这个服务会比实际情况更可靠(例如 Chubby 的例子,参见下面的“全球 Chubby 服务计划内停机”。
另外一种情况是会导致信心不足—用户会认为系统比实际情况更脆弱和不可靠,从而不会去使用它。
全球 Chubby 服务计划内停机 作者:Marc Alvidrez
Chubby 是 Google 的一个分布式锁服务,用于松散耦合的分布式系统。在全球 Chubby 服务中,我们将 Chubby 实例的副本分布在不同的地理区域。随着时间的推移,我们发现,全球实例出现问题经常会导致其他服务出现故障,其中很多故障都会影响到外部用户。但是,由于真正的全球 Chubby 服务故障出现的频率太低,以至于其他服务负责人开始认为全球 Chubby 服务永远不会出故障,从而不停地将更多的服务依赖于此。Chubby 全球服务的高可靠性实际上提供了一种安全假象,因为这些服务实际上在 Chubby 全球服务不可用的时候不能正常工作,不管这种情况是多么罕见。
我们在这里采用了一个很有趣的解决办法:SRE 保证全球 Chubby 服务能够达到预定义的 SLO,但是同时也会确保服务质量不会大幅超出该 SLO。每个季度,如果真实故障没有将可用性指标降低到 SLO 之下,SRE 会有意安排一次可控的故障,将服务停机。利用这种方法,我们可以很快找出那些对 Chubby 全球服务的不合理依赖,强迫服务的负责人尽早面对这类分布式系统的天生缺陷。
协议(SLA)
最后,SLA 是服务质量协议(Agreement):指服务与用户之间的一个明确的,或者不明确的协议,描述了在达到或者没有达到 SLO 之后的后果。这些后果可以是财务方面的——退款或者罚款,也可能是其他类型的。
SLO 与 SLA 的区别
区别 SLO 和 SLA 的一个简单方法是问“如果 SLO 没有达到时,有什么后果?”如果没有定义明确的后果,那么我们就肯定是在讨论一个 SLO,而不是 SLA。
SRE 通常不会参与 SLA 的书写,因为 SLA 是与业务产品的决策紧密相关的。但是,SRE 确实会参与帮助避免触发 SLA 中的惩罚性条款。同时,SRE 会参与制定具体的 SLI:很明显,提供一个客观的方式来度量 SLO 是很重要的,否则大家就会产生分歧。
具体示例
Google 搜索服务是没有公开 SLA 的一个典型服务:我们当然希望所有人都能够最方便、最快地使用 Google 的搜索服务,但是我们并没有与全世界签订合同。但是,即使如此,如果搜索服务不可用依然有后果产生—对 Google 形象有损害,同时也会使得广告业务收入下降。
很多其他的 Google 服务,例如 Google for Work,具有明确的用户 SLA。
不管某个服务是否具有 SLA,定义 SLI 与 SLO,并且用它们来管理服务质量都是很有价值的。
理论说了这么多,终于可以开始讲一些实践经验了。
二、SLI 在实践中的应用
既然我们已经详细描述了为什么选择合适的指标度量服务质量是很重要的,那么究竟如何来识别哪些指标对服务是最重要的呢?
运维人员和最终用户各关心什么
我们不应该将监控系统中的所有指标都定义为 SLI;只有理解用户对系统的真实需求才能真正决定哪些指标是否有用。
指标过多会影响对那些真正重要的指标的关注;
而选择指标过少则会导致某些重要的系统行为被忽略。
一般来说,四五个具有代表性的指标对系统健康程度的评估和关注就足够了。
常见的服务,根据它们的相关 SLI 通常会归类为以下几个大类。
用户可见的服务系统,例如莎士比亚搜索服务的前端服务器通常关心可用性、延迟,以及吞吐量。换句话说:是否能正常处理请求?每个请求花费的时间是多少?多少请求可以被处理?
存储系统通常强调:延迟、可用性和数据持久性。换句话说:读写数据需要多少时间?我们是否可以随时访问数据?数据是否一段时间内还能被读取?
大数据系统,例如数据处理流水线系统,一般来说关心吞吐量和端到端延迟。换句话说:处理了多少数据?数据从输入到产出需要多少时间?(某些流水线任务还会关注某个单独处理阶段的延迟。)
所有的系统都应该关注:正确性。是否返回了正确的回复,是否读取了正确的数据,或者进行了正确的数据分析操作。正确性是系统健康程度的一个重要指标,但是它更关注系统内部的数据,而不是系统本身,所以这通常不是 SRE 直接负责的。
指标的收集
利用某种监控系统,大部分指标数据都在服务器端被收集,例如 Borgmon 或者 Prometheus。或者利用某种日志分析系统,例如分析日志中 HTTP 500 回复所占的比例。
然而,某些系统可以加入对客户端数据的收集,否则可能会错失一些不影响服务器端指标,但是对用户产生影响的问题。例如,只关注莎士比亚服务器搜索后端的延迟可能会错失由页面 JavaScript 脚本导致的用户可见的延迟问题。在这个例子中,度量页面在浏览器中可用的延迟是度量用户体验的一个更好的指标。
汇总
为了简化和使数据更可用,我们经常需要汇总原始度量数据。汇总过程应该非常小心。
某些指标的汇总看起来是很简单的,例如每秒服务请求的数量,但是即使这种简单度量也需要在某个度量时间范围内进行汇总。该度量值是应该每秒获取一次,还是每分钟内的平均值?
后者可能会掩盖仅仅持续几秒的一次请求峰值。假设某个系统在偶数秒处理 200 个请求,在其他时间请求为 0。该服务与持续每秒处理 100 个请求的服务平均负载是一样的,但是在即时负载上却是两倍。
同样的,平均请求延迟可能看起来很简单,但是却掩盖了一个重要的细节;很可能大部分请求都是很快的,但是长尾请求速度却很慢。
长尾效应
大部分指标都应该以“分布”,而不是平均值来定义。例如,针对某个延迟 SLI,某些请求可能很快,其他的可能会很慢,有时候会非常慢。简单平均可能会掩盖长尾延迟和其中的变化。下图提供了一个例子:虽然常见请求可以在 50ms 完成,但 5%的请求却慢了 20 倍!针对平均值的监控和报警将不会发现任何改变,但是服务的确在长尾延迟上出现了巨大变化(图中最上面的那条线)。
位指标
利用百分位指标可以帮助我们关注该指标的分布性:高百分位,例如 99%和 99.9%体现了指标的最差情况,而 50%则体现了普遍情况(99%百分位是指在原始数据中 99%的数值都满足某种条件。例如请求延迟的 99%为 100ms 指的是,在所有请求中,99%的请求延迟都小于 100ms)。
响应时间的分布越分散,意味着普通用户受到长尾请求延迟的影响就越明显,这可能预示了负载过高情况下出现的排队问题。用户研究显示,用户通常更喜欢速度较慢的系统,而不是一个请求速度抖动很厉害的系统,所以,某些 SRE 团队只关注长尾部分,因为如果 99.9%的系统行为都正常的话,那 50%部分就肯定也是正常的。
关于统计性谬误
一般来说,SRE 更倾向于分析一组数据的百分比分布,而非其算术平均值。长尾效应比算术平均值更有特点,使用百分比分布能够更清晰地进行分析。因为计算机系统的本身特质决定,数据是具有特定分布特点的——例如,请求延迟必须大于 0,同时如果超时设置为 1000ms,则不可能有成功请求超过这个时间。因此,我们不能假设算术平均值和中位数是相等的——它们甚至可能相差甚远!
我们同时也不会假设数据是平均分配的,一切都必须经过验证。某些常见的直觉感觉和近似方法在这里并不适用。例如,如果分布情况和假设不一致,那么根据这个假设做出的操作就有可能频率过高,或者频率过低(例如根据请求延迟将过高的服务器自动重启)。
指标的标准化
我们建议标准化一些常见的 SLI,以避免每次都要重新评估它们。任何一个符合标准定义模板的服务可以不需要再次自己定义 SLI。
汇总间隔:每 1 分钟汇总一次。
汇总范围:集群中的全部任务。
度量频率:每 10 秒一次。
包含哪些请求:从黑盒监控任务发来的 HTTP GET 请求。
数据如何获取:通过监控系统获取服务器端信息得到。
数据访问延迟:从收到请求到最后一个字节被发出。
为了节约成本,应该为常见的指标构建一套可以重用的 SLI 模板,从而使得理解每个 SLI 更简单。
三、SLO 在实践中的应用
我们应该从思考(或者调研)用户最关心的方面入手,而非从现在能度量什么入手。用户真正关心的部分经常是度量起来很困难,甚至是不可能的,所以我们需要以某种形式近似。然而,如果我们只是从可以简单度量的数值入手,最终的 SLO 的作用就会很有限。因此,与其选择指标,再想出对应的目标,不如从想要的目标反向推导出具体的指标。
目标的定义
为了更清晰地定义,SLO 应该具体指出它们是如何被度量的,以及其有效条件。例如,我们可能说:
99%(在 1 分钟的时间范围内汇总)的 Get RPC 调用会在小于 100ms 的时间内完成(包括全部后端服务器)。
99%的 Get RPC 会在 100ms 内完成(这一句与上一句一样,只是利用了 SLI 模板中的信息减少了重复信息)。
如果性能曲线也很重要的话,我们可以指定多个 SLO 目标:
90%的 Get RPC 会在 1ms 内完成。
99%的 Get RPC 会在 10ms 内完成。
99.9%的 Get RPC 会在 100ms 内完成。
如果我们同时具有批处理用户(关注吞吐量)以及在线交互式用户(关注延迟),那么可能应该为每种负载指定单独的 SLO 目标:
95%的批处理用户 Set RPC 应该在 1s 之内完成。
99%的交互式用户 Set RPC,并且 RPC 负载小于 1KB 的应该在 10ms 之内完成。
要求 SLO 能够被 100%满足是不正确,也是不现实的:过于强调这个会降低创新和部署的速度,增加一些成本过高、过于保守的方案。更好的方案是使用错误预算(Error Budget)——对达不到 SLO 的容忍度——以天或者以周为单位计量。高层管理者可能同时也需要按月度或者季度的评估。(错误预算其实就是保证达到其他 SLO 的一个 SLO!)
达不到 SLO 的现象的发生频率对用户可见的服务健康度来说是一个有用的指标。通过每日(或者每周)对 SLO 达标程度的监控可以展示一个趋势,这样就可以在重大问题发生之前得到预警。
SLO 不达标的频率可以用来与错误预算进行对比,利用这两个数值的差值可以指导新版本的发布。
目标的选择
选择目标 SLO 不是一个纯粹的技术活动,因为这里还涉及产品和业务层面的决策,SLI 和 SLO(甚至 SLA)的选择都应该直接反映该决策。同样的,有时候可能可以牺牲某些产品特性,以便满足人员、上线时间(time to market)、硬件可用性,以及资金的限制。SRE 应该积极参与这类讨论,提供有关可行性和风险性的建议,下面列出了一些有用的讨论。
不要仅以目前的状态为基础选择目标
了解系统的各项指标和限制非常重要,但是仅仅按照当前系统的标准制定目标,而不从全局出发,可能会导致团队被迫长期运维一个过时的系统,没有时间去推动架构重构等任务。
保持简单
SLI 中过于复杂的汇总模式可能会掩盖某种系统性能的变化,同时也更难以理解。
避免绝对值
虽然要求系统可以在没有任何延迟增长的情况下无限扩张,或者“永远”可用是很诱人的,但是这样的要求是不切实际的。就算有一个系统能够做到这一点,它也需要花很长时间来设计和构建,同时运维也很复杂——最关键的是,这可能比用户可以接受的(甚至是很开心地接受的)标准要高太多。
SLO 越少越好
应该仅仅选择足够的 SLO 来覆盖系统属性,一定要确保每一个 SLO 都是必不可少的:如果我们无法针对某个 SLO 达标问题说服开发团队,那么可能这个 SLO 就是不必要的。然而,不是所有的产品属性都能用 SLO 表达,用户的“满意度”就很难。
不要追求完美
我们可以随着时间流逝了解系统行为之后优化 SLO 的定义。刚开始可以以一个松散的目标开始,逐渐收紧。这比一开始制定一个困难的目标,在出现问题时放松要好得多。
SLO 可以成为—也应该成为—SRE 和产品团队划分工作优先级的重要参考,因为 SLO 代表了用户体验的程度。好的 SLO 是对开发团队有效的、可行的激励机制。但是一个没有经过精心调校的 SLO 会导致浪费,某团队可能需要付出很大代价来维护一个过于激进的 SLO,而如果 SLO 过于松散,则会导致产品效果很差。SLO 是一个很重要的杠杆:要小心使用。
控制手段
SLI 和 SLO 在决策系统运维时也非常有用:
1.监控并且度量系统的 SLI。
2.比较 SLI 和 SLO,以决定是否需要执行操作。
3.如果需要执行操作,则要决定究竟什么操作需要被执行,以便满足目标。
4.执行这些操作。
例如,如果在第 2 步中,请求延迟正在上涨,无操作的话,会在几个小时内超出 SLO 范围。第 3 步则会测试服务器是否是 CPU 资源不够,同时增加一些 CPU 来分散负载。没有 SLO 的话,我们就不知道是否(或者何时)需要执行该动作。
SLO 可以建立用户预期
通过公布 SLO 可以设置用户对系统行为的预期。用户(以及潜在用户)经常希望知道他们可以预期的服务质量,以便理解该服务是否能够满足他们的要求。例如,某个团队想要开发一个照片分享网站,可能会避免使用一个数据持久性高、成本低,但是可用性低的系统。但是,可能会使用另外一个存档信息管理系统。
为了让用户拥有正确的预期,我们可以考虑使用以下几种策略:
留出一定的安全区:对内使用更高的 SLO,对外使用稍低的 SLO 可以留出一些时间用来响应问题。SLO 缓冲区也可以用来进行可能影响系统属性的重构,例如降低成本以及方便运维等,缓冲区保护我们不会对用户产生直接影响。
实际 SLO 也不要过高:用户一般不会严格按照书本定义的 SLO,而是按照实际情况来构建服务,这在基础设施类服务上非常明显。如果服务的实际性能要比 SLO 宣传得好太多,用户可能会逐渐依赖于现在的假象。我们可以利用主观可控模式减少这种过度依赖。(Google Chubby 服务会用计划内维护来避免过于可用。)同时,可以采取对一些请求限速,或者限制系统在低负载情况下也不会速度过快的手段。
理解系统行为与预期的符合程度可以帮助决策是否需要投入力量优化系统,使其速度更快、更可用,或者更可靠。如果服务一切正常,可能力量应该花在其他的优先级上,例如消除技术债务、增加新功能,或者引入其他产品等。
四、SLA 在实践中的应用
起草一份 SLA 需要业务部门和法务部门选择合适的后果条款。
SRE 在这个过程中的作用是帮助这些部门理解 SLA 的 SLO 达标的概率和困难程度。
许多针对 SLO 的建议也同样适用于 SLA。
最好在用户宣传方面保持保守,因为受众越广,修改和删除一个不合适或者很有困难达到的 SLA 就越困难。
版权声明: 本文为 InfoQ 作者【董哥的黑板报】的原创文章。
原文链接:【http://xie.infoq.cn/article/58e1694c6be8b28f5e8a3f7f6】。文章转载请联系作者。
评论