查看原文
其他

没有SLO就没有SRE?来看看B站SRE对SLO的实践总结(上)

SRE团队 哔哩哔哩技术 2023-01-17

本期作者


武安闯

哔哩哔哩业务SRE负责人

2016年加入B站,深度参与B站微服务拆分、云原生改造、高可用建设、SRE转型和稳定性体系落地等业务。当前主要关注B站在线业务的SRE稳定性体系建设和推广,对SRE的实践有深入的探索与思考。


01 背景


最近几年,Google SRE在国内非常流行。Google SRE方法论中提出了SLO是SRE实践的核心,SLO为服务可靠性设定了一个目标级别,它是可靠性决策的关键因素。那如何选择和计算SLI,如何设置SLO,如何实践落地呢?本文就来讲讲B站SRE在实践SLO时所走的弯路和总结的经验。


02 Google SRE中SLO的定义


服务水平目标(SLO)指定了服务可靠性的目标水平。由于SLO是做出以数据为依据的可靠性决策的关键,因此它们是SRE实践的核心。


上文是Google SRE《站点可靠性手册》中的原文。那为什么需要SLO呢,我们摘取原文中的核心观点:

  • 工程师稀缺,需要把时间投入到重要服务的核心问题上

  • SLO是做出工作优先级排序和可靠性相关工作的关键

  • SRE的核心职责不仅是自动化和处理故障,日常工作都要按照SLO来开展

  • 没有SLO,就没有SRE

为了采用基于错误预算的可靠性工程方法,同样摘取原文中的核心观点:

  • 服务的利益相关方认可此SLO

  • 服务正常状态下可以达到SLO的要求

  • 组织认可错误预算并在决策中发挥作用

  • 有完善的SLO流程

否则,SLO合规性成为一个KPI或报告指标,而不是决策制定工具。请记住这句话,因为我们的弯路就走到这里了。


03 Google SRE中SLO的实施


在《站点可靠性手册》第二章“实施SLO”中,Google详细讲述了如何实施SLO,大致流程如下:

1. SLI选择

  • 对于请求驱动型服务,SLI一般选择可用性(成功响应的请求比例)、延迟、质量

2. SLI计算

  • SLI的计算可以使用应用服务器日志、负载均衡监控、黑盒监控、客户端插件等数据源

  • 一般选择负载均衡监控,因为其代表一个用户请求在整套系统所有模块处理耗时和所有网络传输耗时的总和,且和客户端插件相比,实施成本较低

3. SLO定义

  • 基于计算出来的可用性、延迟数据,来定义合适的服务SLO

  • 服务可用性:例如,全年可用性 > = 99.99%

  • 服务延迟:例如,99%的请求<= 200ms,90的请求< 100ms

  • 可以在不同的时间窗口上定义SLO,比如一个月或一个季度

  • 获得关键的利益相关者认可和批准

4. 错误预算

  • 有了SLI和SLO,时间窗口内的允许失败数就知道了

  • 如果给定时间内错误预算消耗殆尽,要制定错误预算执行策略,如:

    * 开发团队专注于可靠性问题,直到系统处于SLO范围内,功能迭代推迟

    * 为了降低风险,冻结生产系统的变更,直到有了错误预算来支持变更

5. 记录SLO和错误预算

  • SLO的作者,审核人,批准日期,下次审核日期,相关背景

  • 定义和变更有平台、流程、制度、变更事件可回溯

  • SLO的细节:SLI实现、如何计算、如何使用错误预算

  • 错误预算的记录跟上面信息类似

6. 仪表盘和报表

  • 除了已发布的SLO和错误预算,还需要一个报表和仪表盘来做展示

7. 持续改进SLO,提高SLO质量


04 我们的SLO实践


从上文Google对SLO的介绍中,我们抽象出了关键信息来指导我们的建设。


 服务分级


应用:技术视角

  • 一个应用对应一个appid,包括前端和后端应用

  • 编码构建后,可独立部署运行

  • 一个业务,会包含多个应用,一般具有相同的命名前缀或关键词

业务:产品视角

  • 一组网站/APP产品相关功能的聚合

  • 相对独立的业务模块

  • 包含一组相关联的应用

等级分级

我们分为L0-L3四个级别:

  • L0:公司级核心业务,一般是公司级基础服务或公司核心业务场景,如APP推荐、视频播放、支付平台及强依赖业务等

  • L1:部门级核心业务,一般是L0业务体验中依赖的主要业务、核心的二类业务,如视频播放页的一键三连功能、核心二类业务动态、搜索等

  • L2:用户可直接使用的其他业务,如播单、分享、专栏、答题等

  • L3:其他后台类业务或对用户体验无影响的业务

分级对象

  • 先对业务(产品)定级

  • 再对这个业务下的多个应用定级,根据应用所提供的产品功能和故障影响来定,应用等级不超过业务等级

  • 在对此业务中用户所能触达到的API定级,API等级不超过应用等级

分级用途

  • 基于服务等级,要求核心服务遵守对应技术标准

  • 对不同等级的服务,制定不同的变更流程

  • 报警基于服务等级来做分级

  • 要求服务满足稳定性要求,如具备熔断降级能力,具备同城双活能力等

分级运营

  • 其他基础平台展示分级数据,基于服务等级定运行策略

  • 基于分级后的技术标准、流程等反推定级准确率提升


 SLO系统


1. SLI选择

  • 对于在线业务来说,基本都是请求驱动的业务,所以选择可用性、延迟、吞吐

  • 可用性:我们度量了两个指标:错误量、请求成功率

  • 延迟:我们度量了p90和p99两个分位的延迟数据

  • 吞吐:每天的请求总量和单位时间的请求速率

可用性为什么不选择可用时间来度量呢?如果选择时间,一般的做法是在某个时间段内错误率大于多少,则认为这段时间内服务不可用。假如这段时间内某个服务错误率低于阈值但同时有大量用户反馈不可用的话,我们不能掩耳盗铃的认为这段时间服务是可用的。因为无法解决这个问题,所以我们选择了请求成功率。

2. SLI模型

  • 应用的API是业务功能的直接体现,通过度量API的SLI就能反映出业务某个功能的情况

  • 选择能代表业务核心功能的API,按上面的业务分级模型对这些API定级,一般只度量L0、L1等级的业务和其接口

  • 业务一般都会提供多个功能,比如弹幕的读写,评论的读写,所以业务的SLI是由代表业务功能的多个API SLI数据聚合而成的

  • 对于API,我们度量可用性、延迟、吞吐

  • 对于业务,我们通过聚合API 的SLI,主要度量可用性

3. SLI计算

  • 统一标准,使用接入层负载均衡指标。所有面向用户的公网服务都会经过接入层负载均衡,也即SLB(下文统称为SLB)

  • 内网服务东西向调用时通过服务发现直接调用,不过SLB,所以无法用SLB的指标度量。我们认为内网服务的故障最终能在面向用户侧的公网服务中体现出来,所以我们只对面向用户的公网服务做度量

  • API可用性:每分钟计算出API的错误量(HTTP 5XX请求)、总请求量、成功率、分位延迟请求量、吞吐。每天再聚合出一天的错误量、总请求量、成功率、分位延迟请求量、吞吐。有了每天的数据后,可灵活的聚合出API每个季度、半年、全年或某个时间区间的数据

  • 业务可用性:对于业务来说,我们只做错误量、成功率聚合

    * 相同等级的API权重应该是一样的,不同等级的API应该加权

    * 每分钟计算出L0等级API的错误量之和、总请求量之和、总成功率(1 - (错误量之和 / 总请求量之和))

    * 每分钟L1等级的API也聚合出相同的数据

    * 每分钟业务可用性 = (L0 API总成功率 * 权重 + L1 API总成功率 * 权重)/ 总权重

    * 有了业务每分钟的可用性后,再聚合出业务一天的可用性,以及灵活的聚合出每个季度、半年、全年或某个时间区间的数据

4. SLO定义

  • 只对可用性和延迟做SLO定义,吞吐做SLI仪表盘和报表即可

  • 在API分级时,我们会对API设置一个基于分级的默认SLO,比如L0 API 可用性>= 99.99%,L1 API可用性>= 99.99%,L0 API 99分位延迟<=200ms

  • 在业务分级时,我们会让研发对业务设置一个可用性SLO目标,比如全年可用性>= 99.99%

5. 错误预算

  • 我们在一开始尝试SLO时,并没有去重点建设错误预算。只是使用了基于服务分级的SLO错误量和可用性报警

6. 记录SLO和错误预算

  • 我们提供了平台化能力去支持定义SLO时的审核和记录

7. 仪表盘和报表

  • API仪表盘与报表


  • 业务仪表盘与报表


上面一套SLO体系建设完成以后,我们对L0、核心L1业务都做了SLO定义、SLI指标和计算。核心API和业务都具备了SLI报表能力,我们的可用性有了可视化的图表,一切似乎非常美好...但仍存在问题。


05 遇到的问题


1. 业务定级

  • 业务抽象认知不一,产品范围可大可小

  • L0、核心L1业务在SRE的关注下定级基本准确,但其他业务定级就一言难尽了

2. 应用定级

  • 应用数量远多于业务,定级难度更高

  • 老应用等级更新延迟于业务重构或产品迭代

  • 除L0、核心L1应用外,其他应用等级准确率低

3. 接口定级 

  • 接口数量又远多于应用,定级耗时耗力,维护成本高,当时公司还没有API GW平台

  • 同上,接口等级更新延迟于业务重构或产品迭代

4. SLI计算

  • 当服务因上下游调用依赖导致请求失败时,API的HTTP CODE可能是200,真实的错误被封到了业务错误码中。SLB作为通用的负载均衡,不会去解析HTTP Body

  • 这就导致一个问题:服务故障了半个小时,但今天的可用性却是100%,可用性SLI指标没受到任何影响,SLO也完全符合要求

  • 如果我们改用应用上报的Metrics(内部使用Prometheus),可以解决此问题。但当应用不可用,无法上报Metrics时,也会获取不到数据,导致SLI数据不准确

  • 我们试过推研发把业务错误码中的系统错误(调用依赖类的系统错误,而非业务逻辑错误)改为HTTP CODE,但成本极高,跟微服务的标准也不相符

5. 业务SLI

  • 需要筛选出影响业务核心功能的API,这些API的SLI数据再聚合到业务,其他API的SLI数据不影响业务SLI 

  • 业务迭代导致API变更,原API SLI不再代表业务功能,导致业务SLI数据没价值

6. 总结一下遇到的问题

  • 分级模型过于理想,定级成本高

  • 业务SLI关联关系、API SLI元信息更新不及时,数据准确率低

  • 无法通过一条Metrics计算到的可用性SLI来覆盖业务全部故障场景

  • 部分部门的业务只提供内网服务,不直接对用户,导致没有SLI数据

  • SLI数据好像除了当报表外,也没什么价值

最后压死我们SLO体系的稻草是一个业务需求:把业务的可用性SLI作为业务年度可用性总结报表,替代基于故障时间计算出的业务年度可用性。此需求我们认为是合理的,因为我们度量了业务可用性SLI,那算出的可用性当然可以作为业务年度总结报表来使用了。但我们在实际使用数据时遇到了一个问题:

假设某业务正常情况下一天的总请求是24W,此业务某天故障了半个小时,这半个小时在未故障时的请求量是1W,故障时因为用户或链路上的重试导致接入层负载均衡收到的故障请求为2W

  • 基于请求成功率算出的当天业务可用性:( 1 - 2W / ( 24W + 1W) ) * 100% = 92%,假设此业务一年内其他时间日请求不变,每天都是100%可用性,则此业务全年可用性为:1 - (2W / ( 25W + 24W * 364))  = 99.977%

  • 基于故障时间算出的当天业务可用性为:( 1 - 0.5 / 24 ) * 100% = 97.916%,假设此业务全年其他时间每天都是100%的可用性,则此业务全年可用性为:( 1 - 0.5 / 24 / 365 ) * 100% = 99.994%

可以看出,两种计算方式得出的可用性差距极大。为了解决这个问题,我们想到了一种数据补偿机制:基于故障时段的同环比数据对故障损失数据去重,尽量向故障时间数据靠齐。去重后基于请求成功率数据结果为:

  • 忽略重试增加的1W请求量,则当天业务可用性:( 1 - 1W /  24W ) * 100% = 95.833%,假设此业务一年内其他时间日请求不变,每天都是100%可用性,则此业务全年可用性为:1 - (1W / ( 24 * 365))  = 99.988%

此方式虽然依旧无法跟基于故障时间的可用性数据对齐,但已经非常接近了,我们认为加上了数据补偿机制之后,统一用这个计算标准的话,业务的可用性SLI是可以作为业务年度可用性报表使用的。想法又一次非常美好...

实际运作起来时,我们发现成本太高了。当发生了影响业务核心功能的事故,我们就要对故障数据去重,然后修订故障当天的SLI数据。需要有人去盯着事故报告的损失,跟研发一起核对损失数据,再修订SLI数据.....

最终,因为我们执着于提升SLI的准确率,导致整个SLO系统无法运转......此时我们的SLO体系开始停滞和崩溃.....


06 反思


我们开始反思问题出在了哪里,SLO的价值到底是什么?SLI度量的对象到底是什么?是业务吗,还是应用?Google 基于错误预算做了消耗率报警,我们的SLO除了做报表外好像没啥价值?想清楚这些问题后我们才意识到之前为什么走偏了。

SLO是可靠性决策的关键因素,但不是非有不可

  • 在没有SLO、SLI之前,我想大家的稳定性工作也能分的清楚优先级,比如基于事故复盘来决策高可用工作方向,如服务降级、熔断、中间件高可用、多活容灾等

SLO的价值绝对不是报表,而是及时报警,发现影响SLI指标的异常

  • SRE中有一章专门讲基于SLO的报警,但在我们的实践中却忽略了这个方向,执着于提升SLI指标的准确率

  • 应用每天都有无数的报警通知,如CPU、内存、磁盘、调用超时、请求错误、请求重试等,产生了大量噪音。但哪些报警会影响到可用性SLI需要SRE和研发关注呢?我想这就是SLO的核心价值之一了

错误预算策略是诗与远方

  • 如果业务某个季度发生事故,把这个季度的错误预算耗尽,SLO已不符合预期,SRE也不能冻结这个业务的变更

  • 至于调整业务团队的短期目标,从业务迭代转到专注于可靠性问题还是可以的。但这个目标一般是事故驱动达成的共识

  • 如果让国内互联网公司产品迭代停止三个月,我想没有哪个公司会同意

SLI度量的核心是业务功能和应用,而不是聚合业务SLI

  • API是业务功能的直接体现,通过度量API的SLI就能反映出业务某个功能的情况

  • 业务功能不可能全部枚举出来,接口也不可能全部定级和计算SLI。但应用是有限且标准的,基于应用的Metrics即可算出所有应用的可用性SLI

  • 业务核心功能的SLI通过API SLI已度量出来,是否要聚合成一条代表业务SLI的指标其实并不重要。比如在业务报表页面展示业务多个功能的API SLI数据可能会更直观

  • 业务SLI的核心价值是NOC/技术支持团队在Oncall时的关注指标,或构建业务场景监控时从业务指标到技术指标的下钻串联,更偏向运营层面


07 总结


本文详细介绍了我们在实践SLO体系时的思路、落地方法以及遇到的问题。我们在没彻底理解SLO及其价值的情况下,就尝试建设SLO体系,走了很多弯路,反思阶段我们也认清了SLO的价值。下一篇会讲述在新认知下的SLO体系建设思路,敬请期待~


往期回顾:2021.07.13 我们是这样崩的





您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存