SLO(服务等级目标)衡量一个平台的可靠性。本章将介绍如何将SLO转化为重要事件的报警规则。本文例子展示了一系列复杂的监控报警和逻辑执行过程,并讨论每个实用性与缺点。但例子使用了一种简单的请求驱动的服务和Prometheus语法,你可以将该方法应用于任一报警框架。
报警注意事项
为了生成源于服务等级指标(SLI)和错误预算(允许故障的数量)的报警,需要将两者结合为一。目标是收到某种重要事件(占用了大部分错误预算的事件)的提醒。
衡量一个报警策略,需考虑以下指标:
精确度:是否每个报警100%对应于一个重要事件。注意,报警在低流量阶段会对不重要的事件变得尤其敏感。
报警率:是否每个重要事件都能100%触发一个报警。
检测时间:在不同情况下发送报警提醒的所需时间。过长的检测时间会长期占用错误预算。
恢复时间:一个问题解决后,报警还将维持多久。过长的恢复时间将产生混淆或忽略了其它问题。
重要事件报警的方法
为SLO设置报警规则会变得十分复杂。为了在上述四种指标上都有很好的表现,提供了六种方法为重要事件配置报警。
1. 目标错误率≥SLO阈值(不建议)
最简单的方法,就是选取一个较小的时间窗口(例如10min),并且该窗口的错误率超过SLO阈值时报警。
下图展示了检测时间与错误率的关系。例子中报警窗口大小为10min,SLO为99.9%。
利:检测时间佳,整个中断事件为0.6s。所有影响SLO的事件都能触发报警。
弊:精确性很低。触发了大量无效报警。
2. 增大报警窗口(不建议)
增加报警窗口的大小,并相应地提高错误率。
利:检测时间良好,同时提高了方法1的准确性。错误率更高的事件才会触发报警,更有可能为重要事件。
弊:在100%中断的情况下,报警会在2min后触发,同时在未来的36h内会持续报警。
存储或I/O操作具有大量数据点,在更大的窗口计算其错误率的成本可能很高。
下图展示了错误率在整个36h来看,已经微乎其微,但36h的平均错误率依然高出阈值。
3. 增加报警持续时间(不建议)
多数报警系统允许在报警规则种添加报警持续时间的参数,所以该报警只有在阈值被超过一段时间后才会触发。使用该参数可以用一种相对廉价的方式延长窗口。
利:报警的准确性提升。
需要持续的错误率才能触发报警,意味着该报警对应一个重要事件。
弊:由于持续时间无法随着事件的严重性伸缩,一个100%的中断在一小时以后才触发报警,同样的检测时间仅为0.2%个中断。100%的中断会占用该小时30天预算的140%。
如果监控项的值能马上降低到SLO范围内的水平,持续时间的计时器重置,则该波动情况将永远无法触发报警。
下图展示了某服务5min窗口的平均错误率,持续10min后才触发报警。一系列100%的每10min持续5min的错误,尽管消耗了35%的错误预算,却不能成功触发一次报警。
4. 基于消耗速率的报警(可用)
为了改进上述方法,建立具有良好检测时间和高精确度的报警,可以引入消耗速率减少窗口大小,同时使得报警预算的消耗处于常量。
消耗速率指的是服务消耗相对于SLO的错误预算的速度。下图为消耗速率与错误预算的关系。
消耗速率为1的服务,意味着它消耗错误预算的速度使得在SLO的窗口最末,刚好预算剩余量为0。一个满足99.9%SLO的30天的时间窗口,以0.1%的错误率可以刚好消耗所有的错误预算。
下表展示了消耗速率与对应错误率和消耗SLO预算的时间。
通过固定报警窗口1个小时,并且认为占5%错误预算便需触发报警,那么就能将消耗速率应用于报警中。
基于消耗速率的报警,触发报警所消耗的时间为:
报警触发时间占用的错误预算为:
因此一个小时占用了一个30天错误预算的5%,消耗速率为36。
报警规则现在变为:
利:精确度高,大部分错误预算都用于重要事件的报警。
时间窗口更短,更易计算。
检测时间良好。
恢复时间为58min,有所提高。
弊:报警率低,消耗速率为35的将永远不报警,但又在20.5h以内消耗完30天的错误预算。
恢复时间仍然太长。
[if !supportLists]1. [endif]多个消耗速率的报警(可用)
报警逻辑可以使用多个消耗速率与时间窗口,当消耗速率超过一定阈值的时候可以触发报警。这样可以保留基于消耗速率报警的有点,也能保证错误率更低的但依然重要的事件不被忽略。
另一个好办法是,为一些可以消耗错误预算但不被发现的事件设置标签——例如3天内消耗了10%的预算。该错误率可以捕捉到重要事件,但预算消耗速率又能提供足够的时间解决问题,不需要提醒某人。
我们还推荐1小时内消耗2%的预算和6小时内消耗5%的预算作为page的合理初始数量,3天内消耗10%的预算作为ticket报警的基线。具体的数量取决于服务和基线的page负载。对于较忙的服务,需要忙时闲时都有值班,这时就需要6小时窗口的ticket报警。
下表显示了消耗SLO预算百分比的时间窗口与相应的消耗速率。
此时报警配置类似于:
下图展示了检测时间和对应错误率的报警类型的关系。
多种消耗速率能使你根据需要响应的速度给予报警适当的优先级。如果某个事件在几小时或几天内就能消耗完错误预算,就需要发送提醒。否则,发送基于ticket的提醒,在下一个工作日解决该报警即可。
利:该方法可以根据紧急程度配置,适应多种情况。如果错误率高便立即报警,如果错误率低但持续时间长,最终也会报警。
精确度高,和所有固定预算的报警方法相同。
报警率高,因为时间窗口为3天。
可以基于需要响应的速度选择最适合的报警类型。
弊:更多的数量、窗口大小、需管理和分析的阈值。
恢复时间更长,因为时间窗口为3天。
如果满足所有条件,为避免发送多种报警,需要执行报警抑制。例如,5min内消耗10%的预算同时意味着6h内消耗了5%的预算,1h内消耗了2%的预算。这种场景将会触发三种类型的报警,除非监控系统能够智能感知到并阻止。
6. 多窗口多消耗速率的报警(最佳)
我们需要添加另一个参数——一个更小的窗口查看当报警触发的时候,错误预算是否仍在被消耗。
下图中设置长窗口1/12大小的短窗口。经过了10min的15%错误后,短窗口的平均值立马超出报警阈值,而长窗口的平均值超出阈值是在5min以后,此时报警开始触发。短窗口的平均值在错误停止的5min后回到阈值线以下,此时停止报警。长窗口的平均值在错误停止的60min后才降到阈值线以下。
举个例子,你可以在前1h和前5min超过14.4的消耗速率时发送一个page等级的报警,该报警只在你消耗了2%的预算时触发一次,而恢复时间时在报警触发的5min以后,而不是1h以后。
下表为基于SLO的报警配置的推荐参数。
我们可以发现基于多种消耗速率的报警是实现基于SLO报警的有效方法。
利:一个灵活的报警框架允许你根据时间的紧急程度和组织的需要控制报警的类型。
精确度高,和所有固定预算的报警方法相同。
报警率高,由于窗口大小为3天。
弊:需要指定太多参数,使得报警规则很难管理。
低流量的服务与错误预算报警
例如在夜间与周末,需改变报警策略。在低流量服务中很难自动区分不重要的事件。例如,一个系统每小时收到10个请求,一个请求失败则会导致每小时的错误率为10%。对于99.9%SLO的要求,该请求会导致1000的消耗速率,会马上发送page报警,因为小号了30天错误预算的13.9%。如此一来,30天只能允许7个请求失败。单个请求的失败可以是很多无关紧要的原因造成的,不需要如解决系统中断的方式处理它。
基于系统特性的最佳解决方法:一个失败的请求会造成什么影响?以下给出针对低流量服务的一些关键选择:
生成模拟流量弥补来自真实用户的信号缺失。
出于监控目的,为较大的服务结合小服务。
调整产品,使得它需要发送更多的请求以定义一个事件为一次失败,或者降低一次失败的影响。
生成模拟流量
一个系统可以综合分析用户行为,以检查潜在问题与高时延的请求。当缺少真实用户时,监控系统可以检测综合的问题与请求,所以值班工程师可以在影响到真实用户前对问题做出响应。
模拟流量提供了更多用于工作的信号,允许你使用已有的监控逻辑和SLO指标。你也许已经有了大多数必要的流量生成组件,例如黑盒探针和集成测试。
生成模拟流量也有缺点。大多数保证SRE支持的服务是复杂的,有大量系统控制接口。理论上,系统是利用模拟流量设计与搭建的。就算是重要事件,你也只分析用户请求类型中的一小部分。对于包含多种状态的服务,状态的数量加剧了这个问题。
另外,如果一个时间影响了真实用户却不影响模拟流量,模拟请求将真实用户的信号掩盖了,你就无法接收到用户可见错误的通知。
组合服务
如果多个低流量服务是为了一个功能,将它们的请求结合在一个单独的组可以更精准地检测到重要事件,减少干扰。你可以将属于同一产品的多个微服务组合起来,或是将多个请求类型组合为一个类,将服务关联起来。
组合服务的缺点是,一个单一服务造成的全局失败不能算作一个重要事件。你可以通过选择带有共享失败域的服务,增加一个事件影响组的可能性,例如常见的后台数据库。你仍然可以通过长期报警捕捉到单个服务的100%失败。
改变服务与基础架构
对重要事件采取报警可以在它们消耗全部错误预算之前减轻问题。如果你无法降低监控系统对微小事件的敏感性,生成综合流量是不切实际的。我们需要改变服务,降低用户单个请求失败造成的影响。例如:
改变客户端,让其重新尝试,具有指数退避和抖动。
可以在服务器上或客户端上设置捕捉最终执行请求的退路。
这些方法同样适用于高流量系统,但更适用于低流量系统。因为它们允许错误预算包含了更多的失败事件,采用了监控中的更多数据,事件在变为重要事件之前有更多的响应时间
降低SLO或增大时间窗口
你也许想知道错误预算中的单个失败是否真的对用户造成了影响。如果有少数错误占用了错误预算,你是否真的需要提醒工程师马上修复?如果不,用户对当前的SLO是否满意。降低SLO,工程师只会收到大型持续中断的报警提醒。
当你决定将SLO从99.99%降低至99%,改变非常简单。如果你已经有了基于一个SLO阈值的报告、监控和报警系统,只需要将新的SLO值添加至相关即可。
降低SLO可能会影响系统的其它方面,例如系统行为的期望,误差预算占用策略等。其它要求比起减少低信号报警数量也许更重要。
同样,增大用于报警的时间窗口,可以保证触发page报警的时间更为重要。
我们针对低流量服务使用了以下几种方法:
1. 生成假的流量(当其可行性高并且能获得良好覆盖时)。
2. 改变客户端,降低微小的失败事件对用户造成的影响。
3. 集合小型服务,总结它们共有的失败类型。
4.设置与失败请求的真实影响相匹配的SLO阈值。
极端的可用性目标
具有极低或极高可用性目标的服务需要特殊的考量。例如,假设一个服务具有90%的可用率目标。一小时内占用了2%的错误预算就会发送page报警。由于一个100%的中断消耗了该小时1.4%的预算,这个报警将无法触发。如果报警预算设置的时间段很长,则需要调节报警参数。
因为具有极其高可用性目标的服务,一个100%中断消耗完全部预算的时间非常小。一个服务的100%中断,若其目标为月可用性为99.999%,那么消耗完全部预算只需26s,远小于许多监控服务的监控采集间隔,更别提端到端生成报警并通过邮件和短信发送提醒的时间了。尽管报警直接到达一个自动决策系统,该事件也会在你能解决它之前消耗完全部的错误容量。
收到你仅有26s的预算剩余的消息不一定是坏的,只是不利于SLO的维持。唯一保持可靠性的方法时将系统设计为,出现一个100%中断的可能性极其低。这样,我们就能在消耗完预算之前解决问题。例如,如果你最初将改变用于1%的用户,那么消耗错误预算的速率为1%,距离消耗完错误预算还有43min。设计此类系统的方法见Chapter16。
扩展报警
当你扩展你的服务时,应确保你的报警策略是可伸缩的。你也许想为某些服务设置自定义的报警参数。如果你的服务包含100个微服务(或者一个具有100种不同请求类型的服务),则为不可伸缩。
这种情况下,强烈不建议为每个服务指定独立的报警窗口和消耗速率参数,因为太繁琐耗时(报警参数的临时改变除外,在中断的修复过程做些改变时允许的,在该阶段也无需接受报警提醒)。一旦决定了报警参数,就将其应用于你的所有服务上。
有种管理大量SLO的方法就是将请求类型按相似的可用性要求分组。例如某服务具有可用性与时延的SLO,便可将其请求类型分为以下几种:
CRITICAL: 重要的请求类型,例如用户接入服务的请求。
HIGH_FAST: 请求为高可用性和低时延的,例如用户点击查看本月广告进账清单。
HIGH_SLOW:重要但时延不敏感的功能,例如用户点击生成近几年的所有广告业务的报告,不需要数据立即返回。
LOW: 请求具有一定可用性,但中断对用户不可见。例如用于帐户通知的轮询处理程序发生故障很久,也不影响用户体验。
NO_SLO: 该功能完全不影响用户。例如完全在SLO以外的摸黑启动或阿尔法功能。
通过对请求分组,而不是为所有请求类型配置同一个可用性与时延目标,可以将其分为如下五类。在保证用户体验的同时,降低系统的复杂性和成本。
结论
如果你设置的SLO是有意义的,易理解的,在监控项种体现了的,那么你可以配置报警,使它只在需要采取行动、对错误预算构成威胁的时候才触发并通知值班组。
重要事件的报警方法,从错误率超出SLO阈值到多种消耗速率与报警窗口。大多数时候,我们认为多窗口,多消耗速率报警方法是保障应用SLO的最佳策略。
网友评论