服务级别目标(SLO)详解:如何定义 SLI、SLO 与 SLA
服务级别目标(Service Level Objective,SLO)是 SRE 实践中的核心概念。它与服务级别指标(SLI)和服务级别协议(SLA)共同构成了衡量、管理和改进服务可靠性的基础。本文将介绍如何选择合适的 SLI,如何制定合理的 SLO,以及如何通过 SLA 管理用户预期和业务风险。
如果不了解哪些行为对服务真正重要,以及如何衡量和评估这些行为,就无法正确管理一项服务,更谈不上高效管理。为此,我们需要为用户定义并提供明确的服务级别,无论他们使用的是内部 API,还是面向公众的产品。

服务级别目标(SLO)详解:如何定义 SLI、SLO 与 SLA
我们会结合直觉、经验以及对用户需求的理解,定义服务级别指标(Service Level Indicator,SLI)、服务级别目标(Service Level Objective,SLO)和服务级别协议(Service Level Agreement,SLA)。这些概念分别描述关键指标的基本属性、我们希望这些指标达到的取值,以及在无法提供预期服务时应如何应对。归根结底,选择合适的指标有助于我们在问题发生时采取正确行动,也能让 SRE 团队更有信心地判断服务是否处于良好状态。
本章将介绍我们用于度量建模、指标选择和指标分析的框架。纯粹抽象地解释这些概念并不容易,因此我们将借助《莎士比亚:示例服务》中介绍的莎士比亚服务来阐明主要观点。
服务级别术语:SLI、SLO 与 SLA
许多读者可能已经熟悉 SLA 的概念,但 SLI 和 SLO 也值得仔细定义。原因在于,SLA 这个词在日常使用中含义繁多,不同语境下往往会衍生出不同解释。为了避免混淆,我们在这里将这些概念加以区分。
服务级别指标(SLI)是什么
SLI 是服务级别指标,是对服务所提供水平的某个方面进行精确定义的定量衡量。
大多数服务都会将请求延迟,也就是响应请求所需的时间,视为关键的 SLI。其他常见的 SLI 包括错误率,通常表示为错误请求在所有已接收请求中的比例;以及系统吞吐量,通常以每秒请求数来衡量。这些指标通常需要聚合:在某个测量窗口内收集原始数据,再将其转换为比率、平均值或百分位数。
理想情况下,SLI 应当直接衡量用户真正关心的服务级别。但在某些情况下,我们只能使用代理指标,因为真正需要的指标可能很难获取或解读。例如,与服务器端延迟相比,客户端延迟通常更能反映用户体验,但有时系统只能测量服务器端延迟。
对 SRE 而言,另一类重要的 SLI 是可用性,即服务处于可用状态的时间比例。它通常被定义为格式正确的请求中成功完成的比例,有时也称为成功率。对于数据存储系统来说,持久性同样重要,即数据能够长期保留的可能性。
虽然 100% 的可用性不可能实现,但接近 100% 的可用性通常是可以做到的。业界通常用可用性百分比中 “9” 的个数来表示高可用性。例如,99% 和 99.999% 的可用性分别可称为 “两个 9” 和 “五个 9”。海外某大型云服务公开公布的可用性目标曾达到 “三个半 9”,即 99.95%。
服务级别目标(SLO)是什么
SLO 是服务级别目标,指由某个 SLI 衡量的服务级别目标值或目标范围。因此,SLO 的自然形式通常是:
SLI ≤ 目标值 或:下限 ≤ SLI ≤ 上限
例如,我们可以决定让莎士比亚服务“快速”返回搜索结果,并设定一个 SLO:搜索请求的平均延迟应小于 100 毫秒。
选择合适的 SLO 并不简单。首先,并非所有指标的目标值都由你决定。对于来自外部世界的 HTTP 请求,每秒查询数(QPS)本质上取决于用户需求,因此无法直接为它设定 SLO。
另一方面,你可以设定一个目标,例如希望每个请求的平均延迟低于 100 毫秒。这样的目标会反过来影响技术选择:它可能促使你编写具备低延迟特性的前端代码,或者采购某些类型的低延迟设备。100 毫秒显然是一个人为设定的数值,但通常而言,延迟越低越好。我们有充分理由相信,速度快优于速度慢;当用户感知到的延迟超过一定阈值时,用户甚至可能被直接劝退。关于这一点,可参见相关研究中对“速度重要性”的讨论。
不过,事情比表面上更微妙。QPS 和延迟这两个 SLI 在系统内部往往相互关联:更高的 QPS 通常会导致更大的延迟,而且服务在超过某个负载阈值后出现性能断崖式下降,也是很常见的现象。
选择并向用户公布 SLO,有助于管理用户对服务性能的预期。这种做法可以减少用户向服务所有者提出缺乏依据的抱怨,例如“服务太慢”。如果没有明确的 SLO,用户往往会形成自己对理想性能的认知,而这种认知可能与服务设计者和运营者的判断相冲突。
这样的动态可能导致两种极端情况:一种是用户过度依赖服务,误以为服务的可用性高于实际水平;另一种是用户依赖不足,潜在用户误以为系统比实际情况更不稳定、更不可靠。
某分布式锁服务的全球计划性停机案例
作者:海外某工程师
某海外大型科技公司曾为松耦合分布式系统构建了一套锁服务。该服务在全球场景中会被部署到不同地理区域。随着时间推移,团队发现,该锁服务的全球实例一旦发生故障,就会持续引发服务中断,其中许多中断对最终用户可见。
事实证明,这类真正的全球性故障发生频率极低,以至于服务所有者开始添加对该锁服务的依赖,并假定它永远不会宕机。这种高可靠性带来了虚假的安全感:即使该锁服务极少不可用,一旦它真的不可用,依赖它的服务就无法正常运行。
针对这一情况,解决方案很有意思:SRE 确保该锁服务的全球实例达到其 SLO,但不会显著超过 SLO。在任意给定季度中,如果真实故障没有导致可用性低于目标,团队就会有意关闭系统,模拟一次受控停机。这样,在某项服务添加对该锁服务的不合理依赖后,团队能够尽快发现并清除这种依赖。这种做法迫使服务所有者及早正视分布式系统的现实。
服务级别协议(SLA)是什么
最后,SLA 是服务级别协议,是你与用户之间明确或隐含的合同,其中规定了达到或未达到 SLO 时的后果。这些后果最容易识别的形式是经济性的,例如退款或罚款,但也可以采取其他形式。区分 SLO 和 SLA 的一个简单方法是问:“如果没有达到 SLO,会发生什么?” 如果没有明确后果,那么你看到的几乎肯定是 SLO。16
SRE 通常不参与 SLA 的制定,因为 SLA 与业务和产品决策密切相关。不过,SRE 会参与帮助团队避免未达到 SLO 所带来的后果。他们也可以协助定义 SLI:协议中显然需要有客观方法来衡量 SLO,否则就会产生分歧。
某大型搜索服务就是一个重要服务的例子,它并没有面向公众的 SLA。服务团队希望每个人都能尽可能流畅、高效地使用搜索服务,但并没有与全世界签订服务协议。即便如此,如果搜索服务不可用,仍然会产生后果:服务不可用会损害声誉,并导致收入下降。许多其他办公套件类服务则会与用户签订明确的 SLA。无论某项服务是否具有 SLA,定义 SLI 和 SLO,并利用它们来管理服务,都是非常重要的。
理论就说到这里。现在,让我们进入实践。
实践中的服务级别指标:如何选择 SLI
既然我们已经说明了选择合适指标来衡量服务的重要性,那么如何判断哪些指标对你的服务或系统有意义呢?
你和你的用户最关心什么?
不应把监控系统中所有能够追踪的指标都当作 SLI。只有理解用户对系统的需求,才能明智地选择少数几个关键指标。指标过多会让团队难以聚焦真正重要的内容;指标过少则可能遗漏系统的一些重要行为。根据经验,几个具有代表性的指标通常就足以评估和判断系统的健康状况。
根据 SLI 的相关性,服务通常可以分为以下几类:
面向用户的服务系统,例如莎士比亚搜索前端,通常关注可用性、延迟和吞吐量。换句话说:我们能否响应请求?响应需要多长时间?能够处理多少请求?
存储系统通常强调延迟、可用性和持久性。换句话说:读取或写入数据需要多长时间?我们能否按需访问数据?当需要数据时,数据是否仍然存在?关于这些问题的更详细讨论,可参见《数据完整性:所读即所写》。
大数据系统,例如数据处理管道,通常关注吞吐量和端到端延迟。换句话说:正在处理多少数据?数据从摄取到处理完成需要多长时间?某些管道还可能为各个处理阶段分别设定延迟目标。
所有系统都应关注正确性:是否返回了正确答案?是否检索到了正确数据?是否完成了正确分析?正确性作为系统健康状况的一项指标,需要被跟踪。不过,它通常是系统中数据的属性,而不是基础设施本身的属性,因此通常并非 SRE 的直接职责。
如何收集服务级别指标
许多指标最适合在服务器端收集,例如使用时间序列监控系统,或使用开源监控系统,也可以通过定期日志分析来收集,例如统计 HTTP 500 响应在所有请求中的比例。
然而,某些系统也应配备客户端数据收集能力。否则,如果只测量服务器端行为,可能会遗漏一系列影响用户但不会反映在服务器端指标中的问题。例如,如果只关注莎士比亚搜索后端的响应延迟,就可能忽略由页面 JavaScript 问题引起的用户端高延迟。在这种情况下,测量页面在浏览器中变得可用所需的时间,更能反映用户的真实体验。
指标聚合:为什么平均值并不总是可靠
为了便于使用,我们经常对原始测量数据进行汇总,但这一过程需要格外谨慎。
有些指标看似简单明了,例如每秒处理的请求数,但即使是这样的测量,也已经隐含地对测量窗口内的数据进行了聚合。测量结果是每秒记录一次,还是对一分钟内的请求数取平均?后者可能会掩盖只持续数秒的突发流量中的高瞬时请求速率。
假设一个系统在偶数秒内处理 200 个请求/秒,在其他秒内不处理任何请求。它的平均负载与稳定处理 100 个请求/秒的系统相同,但其瞬时负载却是平均负载的两倍。同样,对请求延迟取平均值看似很有吸引力,但会掩盖一个重要事实:大多数请求可能都很快,但仍然可能有相当一部分请求慢得多。
大多数指标最好被视为分布,而不是平均值。例如,对于延迟 SLI,一些请求会被快速处理,而另一些请求必然需要更长时间,有时甚至会慢很多。简单平均值会掩盖这些尾部延迟及其变化。

服务级别目标(SLO)详解:如何定义 SLI、SLO 与 SLA
系统延迟的第 50、85、95 和 99 百分位数。请注意,Y 轴采用对数刻度。
图 4-1 展示了一个例子:虽然典型请求的处理时间约为 50 毫秒,但有 5% 的请求慢了 20 倍!如果仅基于平均延迟进行监控和告警,那么一天中看起来不会出现任何行为变化;但实际上,尾部延迟,即图中最上方的线,发生了显著变化。
使用百分位数作为指标,有助于考察分布的形状及其不同属性。高阶百分位数,例如第 99 百分位数或第 99.9 百分位数,可以显示接近最坏情况的取值;而第 50 百分位数,也就是中位数,则强调典型情况。响应时间方差越大,典型用户体验就越容易受到长尾行为影响;在高负载下,这种影响还会因排队效应而进一步加剧。相关用户研究表明,人们通常更喜欢响应时间略慢但稳定的系统,而不是响应时间波动很大的系统。因此,一些 SRE 团队只关注高百分位数,理由是:如果第 99.9 百分位数表现良好,那么典型体验也必然不会太差。
关于统计谬误的说明
在处理一组数值时,我们通常更倾向于使用百分位数,而不是平均值,即算术平均数。这样做可以帮助我们观察数据点的长尾部分;这些长尾数据通常具有与平均值显著不同,也往往更有价值的特征。
由于计算机系统的固有特性,数据点常常呈现偏斜分布。例如,任何请求的响应时间都不可能小于 0 毫秒;如果超时时间为 1000 毫秒,那么响应时间也不可能超过该超时时间。因此,我们不能假设平均值和中位数相同,甚至不能假设二者彼此接近。
我们尽量避免在未经验证的情况下假设数据服从正态分布,因为这样会导致许多常见直觉和近似方法失效。例如,如果数据分布与预期不符,那么在检测到异常值后采取措施,比如重启请求延迟较高的服务器,可能会执行得过于频繁,也可能执行得不够频繁。
标准化 SLI 指标
我们建议为 SLI 使用通用定义,这样就不必每次都从头推导。任何符合标准定义模板的内容,都可以从单个 SLI 的说明中省略。例如:
聚合间隔:“1 分钟平均值”
聚合范围:“集群中的所有任务”
测量频率:“每 10 秒一次”
包含哪些请求:“来自黑盒监控作业的 HTTP GET 请求”
数据获取方式:“通过监控系统,在服务器端测量”
数据访问延迟:“到达最后一个字节所需的时间”
为了节省精力,可以为每类常用指标构建一组可复用的 SLI 模板。这些模板也能帮助所有人更容易理解某个具体 SLI 的含义。
实践中的服务级别目标:如何设定 SLO
首先要思考,或者主动找出,用户真正关心什么,而不是先考虑你能衡量什么。通常,用户真正关心的内容很难,甚至无法直接衡量,因此你最终只能以某种方式近似表达用户需求。然而,如果只从容易测量的内容入手,最终得到的 SLO 往往不够实用。因此,有时从期望目标出发,反向推导出具体指标,比先确定指标再设定目标更有效。
明确 SLO 目标
为了最大程度地保证清晰性,SLO 应明确说明其衡量方式和生效条件。例如,我们可以这样表述。第二行与第一行含义相同,但利用上一节中的默认 SLI 定义消除了冗余:
99% 的 GetRPC 调用,在 1 分钟内取平均值后,应在 100 毫秒内完成;该指标在所有后端服务器上测量。
99% 的 GetRPC 调用应在 100 毫秒内完成。
如果性能曲线的形状很重要,也可以指定多个 SLO 目标:
90% 的 GetRPC 调用应在 1 毫秒内完成。
99% 的 GetRPC 调用应在 10 毫秒内完成。
99.9% 的 GetRPC 调用应在 100 毫秒内完成。
如果用户的工作负载具有异构性,例如既包括关注吞吐量的批处理管道,也包括关注延迟的交互式客户端,那么为不同类型的工作负载分别定义目标可能是合适的:
95% 的吞吐量客户端发起的 SetRPC 调用应在 1 秒内完成。
99% 的延迟敏感型客户端发起的 SetRPC 调用,在有效载荷小于 1 kB 时,应在 10 毫秒内完成。
要求 SLO 100% 达成既不现实,也不可取。这会降低创新和部署速度,迫使团队采用昂贵且过于保守的解决方案,或者二者兼而有之。更好的做法是允许一定的误差范围,也就是允许 SLO 未达成的一定概率,并按日或按周进行跟踪。高层管理人员可能还会要求按月度或季度评估。换句话说,误差范围本身也可以看作是达成其他 SLO 的一个 SLO。
可以将 SLO 违规率与错误预算进行比较,并将二者之间的差距作为决定何时发布新版本的重要输入。
如何选择合理的 SLO
选择 SLO 并不是一项纯技术活动,因为它涉及产品和业务影响,而这些影响应反映在所选择的 SLI、SLO 和 SLA 中。同样,在人员配置、上市时间、硬件可用性和资金等限制条件下,团队可能需要在不同产品属性之间做出权衡。SRE 团队应参与相关讨论,并就不同方案的风险和可行性提供建议。以下经验有助于让讨论更有成效:
不要根据当前表现来选择目标。了解系统的优点和局限性固然重要,但如果不加反思地接受当前取值,可能会让团队被锁定在一个目标难以实现、且不经过重大重构就无法改进的系统中。
保持简单。SLI 中复杂的聚合方式可能掩盖系统性能变化,也更难理解。
避免使用绝对化表述。我们当然希望系统能够“无限”扩展负载而不增加延迟,并且“永远”可用,但这种要求并不现实。即使是接近这种理想状态的系统,也可能需要很长时间来设计和构建,运行成本也会很高,而且最终可能远远超出用户真正需要,甚至超出用户预期。
尽可能减少 SLO 的数量。选择足够多的 SLO,以充分覆盖系统的重要属性。要能够为所选 SLO 提供有力理由:如果引用某个 SLO 无法帮助团队在优先级讨论中形成判断,那么这个 SLO 可能并不值得采用。17 不过,并非所有产品属性都适合用 SLO 定义。例如,“用户满意度”就很难用 SLO 精确描述。
完美可以等待。随着对系统运行情况的理解不断加深,你可以随时调整 SLO 的定义和目标。与其一开始就设定一个过于严格、最终不得不放宽的目标,不如先设定一个较为宽松的目标,再逐步收紧。
SLO 可以,也应该,成为 SRE 和产品开发人员确定工作优先级的重要驱动力,因为它们反映的是用户真正关心的问题。一个好的 SLO 能有效推动开发团队的工作;但如果 SLO 设计不当,团队可能会为了达成过于激进的目标而疲于奔命,造成工作浪费;如果 SLO 过于宽松,则可能导致产品质量下降。SLO 是一根强有力的杠杆,务必谨慎使用。
用 SLI 和 SLO 建立可靠性控制回路
SLI 和 SLO 是系统管理控制回路中的关键组成部分:
监控并测量系统的 SLI。
将 SLI 与 SLO 进行比较,并判断是否需要采取行动。
如果需要采取行动,就弄清楚为了达到目标应做些什么。
采取行动。
例如,如果第二步显示请求延迟正在增加,而且如果不采取措施,几个小时后就会无法满足 SLO,那么第三步可能包括验证服务器是否受 CPU 限制,并决定增加服务器数量以分摊负载。如果没有 SLO,就无法判断是否需要采取行动,以及何时采取行动。
在研发管理实践中,SLO 不应只停留在监控面板上,还需要与目标管理、需求评审、排期、开发、测试、发布和知识沉淀等流程衔接起来。借助 PingCode 这类智能化研发管理工具,团队可以把研发过程中的目标、需求、项目、测试、发布和 Wiki 知识记录串联起来,让可靠性目标更自然地进入研发流程,并通过数据流转帮助团队持续提升研发效能。
服务级别目标如何帮助设定用户预期
公布 SLO 可以明确系统行为的预期。用户以及潜在用户通常希望了解他们可以从服务中获得什么,以判断该服务是否适合自己的使用场景。例如,一个想要构建照片分享网站的团队,可能希望避免使用某种承诺极高持久性和低成本、但可用性略低的服务;然而,同样的服务可能非常适合用于档案记录管理系统。
为了帮助用户形成合理预期,可以考虑采用以下一种或两种策略。
第一,保留安全余量。使用比对外公布的 SLO 更严格的内部 SLO,可以让团队有余地在长期问题显现之前就加以解决。SLO 缓冲还允许团队在为了成本、可维护性等其他属性而进行性能权衡时,不至于让用户失望。
第二,不要追求过高目标。用户会根据你实际提供的服务,而不是你承诺的服务来做出选择,基础设施服务尤其如此。如果服务的实际表现远远超过其公开宣称的 SLO,用户就会开始依赖当前表现。可以通过以下方式避免用户过度依赖:偶尔有意让系统离线,例如某海外大型科技公司的一项分布式锁服务就因为可用性过高而引入计划性停机;限制某些请求;或者在系统设计上避免其在低负载下表现得过快。
了解系统是否满足预期,有助于决定是否需要继续投入资源来提升速度、可用性和弹性。反过来,如果服务运行良好,也许就应该将工程时间投入到其他优先事项上,例如偿还技术债务、添加新功能或推出其他产品。
SLA 实践:如何管理服务承诺
制定 SLA 需要业务和法务团队为违约行为选择合适的后果和处罚措施。SRE 的职责是帮助他们理解达到 SLA 中 SLO 的可能性和难度。许多关于 SLO 构建的建议也同样适用于 SLA。
在 SLA 落地过程中,团队往往还需要围绕任务、项目、文档、目标、日历、审批和工时等事项进行持续协作。对于更通用的跨团队协作场景,Worktile 这类项目协作系统可以帮助团队把服务承诺拆解为具体任务和项目节奏,减少 SLA 管理停留在文档层面的风险。
在向用户公开承诺时,保持谨慎是明智的。用户群体越广泛,如果后来发现 SLA 不合理或难以执行,要修改或删除它就越困难。
作者提示含AI生成内容。
