mcpField
O
observability-service-reliability

observability-service-reliability

github.com/elastic云与 DevOps6021.1k 次安装今天更新
代码仓库

关于 observability-service-reliability

使用 Elastic 可观测性工具设计和运营服务可靠性目标的技能。它根据用户可感知的问题和数据选择合适的监测手段,并通过 Kibana 管理 SLO 和消耗速率告警。

主要功能

  1. 01在 SLO、规则、异常任务和合成监测间选择
  2. 02验证指标字段与实测历史
  3. 03设定 SLO 目标、窗口和预算方式
  4. 04创建和管理 SLO
  5. 05关联消耗速率告警规则

适用场景

  1. 01为用户可感知的结果定义 SLO
  2. 02为容量阈值选择监测方式
  3. 03为 SLO 添加消耗速率告警
  4. 04通过合成监测检查端点可用性

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/elastic/agent-skills --skill observability-service-reliability

安装后在 Claude Code 中输入/observability-service-reliability确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
burn-rate-rules.md
documentation.md
slo-api-schemas.md

详细介绍

服务可靠性

设计人们真正会采取行动的可靠性目标,并据此开展运维。本技能涵盖 API 调用前的判断——现有数据适合哪种服务级别指标、什么目标切实可行而非好高骛远,以及服务级别目标是否真是合适的工具——随后介绍如何通过 Kibana API 创建、设置告警、重置和退役 SLO。

可靠性工具不可互换。SLO 根据可消耗的预算衡量用户可见的结果;阈值规则在原始条件满足时触发;异常检测作业会在没有固定阈值的情况下发现偏差;而在四种工具中,只有合成监控器能够检测到已完全停止发送遥测数据的服务。选错工具会产生技术上正确、运维上却毫无用处的告警。若要诊断已经降级的服务,或处理事件本身,请使用 observability-sre-triage 技能;若要了解一般规则生命周期操作,请使用 kibana-alerting-rules 技能。

环境配置

本技能通过 elastic CLI 执行 Elasticsearch 操作。如果未安装 elastic CLI,请告知用户为何需要它。不要猜测凭据、直接调用 HTTP API,也不要尝试其他变通方法。

本技能以 HTTP 简写形式引用操作(例如,GET /、GET /_cat/indices、GET /{index}/_mapping、GET /{index}/_settings/index.mode、POST /_query)。本文末尾的 操作 表格列出了每种简写对应的 elastic CLI 命令——始终使用 CLI,而不要直接调用 HTTP API。

无法访问集群时进行分析

上述 CLI 检查是访问集群进行 查询 的前提,但不影响分析。如果用户已在问题中提供证据(指标值、计数、状态原因、日志行、告警载荷、配置),请根据这些证据进行推理并给出结论。

如果确实需要用户未提供的数据,仍要说明需要检查什么以及如何检查——指出能够明确问题的具体查询、索引和字段,然后再请求配置 CLI。说明检查内容的回答在无法访问集群时仍然有用;只要求配置 CLI 则不然。

SLO 和告警操作针对 Kibana 执行,并使用 kbn: 前缀(例如,POST kbn:/api/observability/slos);数据验证针对 Elasticsearch 执行,使用不带前缀的路径(例如,POST /_query)。Kibana SLO 命令按空间划分——请显式传入空间。对于非默认空间,HTTP 路径变为 kbn:/s/<space_id>/api/observability/slos。

每种 SLI 类型的完整请求正文架构见 references/slo-api-schemas.md,消耗速率规则架构见 references/burn-rate-rules.md,精选的官方文档见 references/documentation.md。

要完成的任务

  • 将可靠性问题转化为合适的工具:SLO、消耗速率规则、阈值规则、异常检测作业或合成监控器
  • 根据服务和数据形态选择 SLI 类型,并在确定方案前验证底层字段
  • 根据实测历史,设置合理且经得起推敲的目标、时间窗口和预算计算方法
  • 决定是否对 SLO 分组,并拒绝高基数分组
  • 创建、验证、更新、重置、禁用和删除 SLO
  • 添加消耗速率告警规则,将快速消耗和缓慢消耗窗口路由到不同严重级别
  • 确保告警界面信号密集:移除重复覆盖,使用暂停而非禁用,并删除无法采取行动的规则
  • 使用合成监控器监控面向用户的端点可用性,并将监测结果纳入可用性 SLI

输出规范

适用于此技能生成的每个回复。

  • 坚持最有依据的结论。 推荐一种 SLI 设计并为其辩护。不要平等列举所有 SLI 类型,然后把选择留给用户——那不是推荐,而是菜单。
  • 说明你选择的目标和时间窗口,以及选择理由,只说一次。 不要在每个要点中重复说明理由。
  • 不要臆造字段名。 写入指标前,先根据映射验证每个字段。若无法确认某个字段,请说明并停止;看似合理的字段名也不如坦承信息缺失。
  • 不要超出证据范围进行推测。 如果测得的历史数据不足以支持某个目标,请说明数据实际支持什么结论。
  • 如实报告数据缺失。 事件数为零,意味着数据缺失或服务未发出事件;绝不意味着服务运行正常。基于总事件数为零计算出的 SLI 比率是未定义的,不是 100%。
  • 不要凑字数。 不要复述问题,也不要描述运行了哪些查询,除非结果与结论有关。
  • 以结论收尾。 不要在结尾附上“要我帮你设置吗?”之类的提议。可执行的后续事项应放在建议列表中,并以建议的方式表述,而不是提问。

流程:将可靠性问题分配给合适的工具

在设计任何内容之前先执行此步骤。大多数糟糕的 SLO 都是乔装打扮的阈值规则。

  1. 明确用户可感知的症状。 询问用户或下游消费者会注意到什么,并因此提出投诉。如果答案是资源数值,而非使用体验——磁盘使用率达到 90%、堆内存持续增长、副本延迟——那么这是容量上限问题,不是可靠性目标。将其交给阈值规则处理。

  2. 检查是否已有覆盖。 使用 GET kbn:/api/observability/slos 列出 SLO,使用 GET kbn:/api/alerting/rules/_find 列出告警规则,并使用 GET /_ml/anomaly_detectors 列出异常检测作业。在已覆盖的信号上再添加第二种工具,是产生重复告警的最常见原因。

  3. 选择工具。

    问题工具原因及代价
    想要按周预算的、用户可感知的成功率或延迟结果SLO + 消耗速率规则提供可消耗的预算和历史记录,并控制变更速度。代价是需要转换,需要稳定的流量,而且有意设计得较慢——即使是快速消耗,也使用一小时窗口。
    有已知安全值且需要立即采取操作的硬性上限阈值或自定义规则在一个调度间隔内触发,无需转换。但它没有预算,也没有记忆,因此只要条件持续成立就会反复触发。
    没有固定阈值、季节性强或涉及许多实体的信号异常检测作业可发现未知异常并适应季节性。需要数周历史数据才能可靠运行,并输出分数而非结果,因此不适合用于告警通知。
    从自有遥测系统外部检查面向用户的端点是否可访问Synthetics 监控唯一能检测完全中断的工具。需要消耗检查预算(参见 Synthetics 部分),且无法解释内部的部分故障。
    没有消费者契约的内部作业,或仍在每日变更的服务无没有负责人和稳定基线的 SLO 会一直显示为红色,最终被忽略,这比没有 SLO 更糟。
  4. 不要忽略中断情况。 基于服务自身日志或追踪构建的 SLI 无法检测服务消失:没有事件时就没有 total,因此比率未定义,SLO 既不会消耗预算,也不会恢复。对于面向用户的服务,每个基于请求的 SLO 都应配合 Synthetics 可用性监控或无数据阈值规则。这是同一信号使用两种工具是正确做法、而非重复覆盖的唯一情况。

流程:设计 SLO

  1. 定位数据并确认字段存在。 使用 GET /_resolve/index/<pattern> 解析索引模式, 然后使用 GET /<index>/_mapping 或 GET /_field_caps 确认指标将引用的每个字段都存在。OTel 原生数据位于 traces-*.otel-*、metrics-*.otel-* 和 logs-*.otel-* 中,三者都填充了 service.name; APM 汇总指标位于 metrics-service_summary.1m.otel-*、metrics-service_transaction.1m.otel-*、 metrics-transaction.1m.otel-* 和 metrics-service_destination.1m.otel-* 中。不要因为状态码、持续时间 或结果字段通常都会存在,就想当然地认为它们存在——请先确认。字段名错误会导致 SLO 计算正常,却毫无意义;缺失字段会如何出错 详细说明了具体情况。

    有两个字段的位置尤其需要留意,因为人们经常猜错:http.response.status_code 位于 traces-*.otel-* 中,不在 logs-*.otel-* 中;transaction.duration.us 位于 traces-*.otel-* 中, 不在 metrics-*.1m.otel-* 汇总数据中,后者包含的是 transaction.duration.histogram 和 transaction.duration.summary。请对照当前部署确认这两个字段,而不要盲目相信此列表。

  2. 先用 ES|QL 验证 SLI,再创建任何内容。 使用 POST /_query 对近期历史数据运行良好请求数/总请求数比率, 以了解测得的基线。此查询用于探索,使用的是 ES|QL,而非 KQL:

    FROM traces-*.otel-*
    | WHERE service.name == "cart" AND kind == "Server" AND @timestamp >= NOW() - 30 day
    | STATS total = COUNT(*), good = COUNT(*) WHERE http.response.status_code < 500
    | EVAL achieved = good::DOUBLE / total
    

    在 OTel 演示集群上,该查询返回 total: 1393887、good: 1393887、achieved: 1.0。这是第 4 步的实测输入, 不是应照搬的目标——连续 30 天表现良好,说明目标应低于 100%,而非设为 100%。

    HTTP 状态码位于 traces 中,不在 logs 中。 http.response.status_code 在 traces-*.otel-* 中有值。OTel 日志 记录不包含 HTTP 状态码,因此 logs-*.otel-* 中根本不存在此字段;而 traces 中该字段的覆盖情况因服务而异:只有 HTTP 服务器发出的 span 才包含此字段。筛选 kind == "Server" 可以保留该服务自己的入站请求,并排除报告其对其他服务发起调用状态的客户端 span。在基于此字段构建指标前,请确认特定服务的覆盖情况:

    FROM traces-*.otel-*
    | WHERE service.name == "cart" AND kind == "Server" AND @timestamp >= NOW() - 24 hour
    | STATS spans = COUNT(*), with_status = COUNT(http.response.status_code)
    

    在同一集群中,cart 返回 spans: 46420, with_status: 46420,而作为 gRPC 服务的 checkout 返回 spans: 4887, with_status: 0。当 with_status 为 0 时,就没有 HTTP 状态码可用于设定预算。请使用 sli.apm.transactionErrorRate,或基于 event.outcome 构建比率;无论使用哪种协议,该字段都会在每个 OTel span 上填充:

    FROM traces-*.otel-*
    | WHERE service.name == "checkout" AND kind == "Server" AND @timestamp >= NOW() - 30 day
    | STATS total = COUNT(*), good = COUNT(*) WHERE event.outcome == "success"
    | EVAL achieved = good::DOUBLE / total
    

    该查询返回 total: 147009、good: 146996、achieved: 0.9999。请将 good 写成肯定形式(== "success"), 不要写成对 "failure" 的否定——空值 outcome 不能算作良好结果。

    这种差异并非 Serverless 独有,也并非只出现在某个演示应用中。在 Stack 9.4.4 集群中,对 traces-*.otel-* 中所有服务的 kind == "Server" 进行相同测量,结果如下:

    ServiceServer spanshttp.response.status_code coverageevent.outcome coverage
    catalog49,2710%100%
    gateway37,773100%100%
    orders37,754100%100%
    payments34,710100%100%
    recommendations34,6920%100%
    shipping34,531100%100%
    六个服务中有两个完全没有 HTTP 状态码,而六个服务的每个 span 上都有 event.outcome。如果基于 http.response.status_code < 500 为 catalog 构建可用性 SLO,计算结果将是 good: 0、total: 49271——达成的 SLI 为 0%,错误预算已全部耗尽,燃烧速率规则会针对健康服务持续触发告警。API 响应和 SLO 界面都不会对此作出提示;分子只会始终为零。每次都要针对具体服务运行上面的覆盖率检查;如果要编写一个指标来覆盖多个服务,优先使用 event.outcome。

    切勿用看似合理的状态字段替代缺失字段——请参阅缺失字段如何导致失败,了解这会带来什么后果。

    还要检查流量是否足够密集,使比率具有意义。如果流量最少的时间桶中只有少量事件,那么一次失败就会让 SLI 波动整整几个百分点,SLO 也会变得毫无参考价值:

    FROM traces-*.otel-*
    | WHERE service.name == "cart" AND kind == "Server" AND @timestamp >= NOW() - 7 day
    | STATS events = COUNT(*) BY bucket = BUCKET(@timestamp, 1 hour)
    | SORT events ASC
    | LIMIT 10
    

    明确限定这个查询。如果没有 @timestamp 谓词,它会对整个跟踪数据流的保留期进行分桶:在演示集群上成本很低,在客户集群上则代价高昂。

  3. 根据数据形态选择 SLI 类型,而不是根据个人偏好。

    SLI 类型适用场景
    sli.kql.custom原始日志或文档,其中的良好请求数和总请求数可通过事件筛选条件表示
    sli.metric.custom预聚合指标字段,其中的良好请求数和总请求数可通过求和或计数的等式表示
    sli.metric.timeslice按时间片与阈值比较的指标,例如 p95 延迟上限
    sli.histogram.custom直方图字段,使用范围表示良好请求数,并使用值计数表示总请求数
    sli.apm.transactionDuration基于毫秒阈值衡量 APM 事务延迟
    sli.apm.transactionErrorRateAPM 事务成功率
    sli.synthetics.availability面向用户的端点的 Synthetics 监控运行时间

    如果适用,优先选择 APM 或 Synthetics 类型:它们会为你处理服务、环境和事务维度,并且在底层索引布局发生变化时仍能保持正确。只有当结果仅在原始事件中可见时,才使用 sli.kql.custom;如果服务已经自行发出计数器,则使用 sli.metric.custom。

  4. 设定可实现的目标。 取第 2 步测得的基线,将目标设为与基线持平或略低于基线;等服务达到目标后,再逐步提高。目标高于测得的基线,会导致预算在第一天就全部耗尽,SLO 永远显示为红色,团队也会停止关注它。objective.target 是介于 0 和 1 之间的小数——应写成 0.995,而不是 99.5。根据目标隐含的 30 天错误预算检查其合理性:

    目标30 天错误预算
    99%7h 12m
    99.5%3h 36m
    99.9%43m 12s
    99.95%21m 36s
    99.99%4m 19s

    如果一次滚动部署、节点重启或依赖项短暂故障造成的损失就超过全部预算,那么这个目标便无法实现,应予以拒绝,而不是附带保留条件后接受。

  5. 选择时间窗口。 timeWindow.type 为 rolling(7d、30d、90d)或 calendarAligned(1w、1M)。 滚动窗口会持续向前移动,因此预算会逐步恢复,消耗速率告警也能保持有效——这是所有运营场景的默认选择。日历对齐窗口会在周期边界重置,适合契约或月度报告的表述,但会在每月第一天造成预算断崖。用于分页告警时选择滚动窗口;只有在确实有人按日历周期报告时,才额外添加日历对齐 SLO。

  6. 选择预算计算方法。 occurrences 会根据整个窗口内的总事件数计算良好事件所占比例,因此流量高峰时段的影响更大,而夜间的低流量故障几乎不会体现。timeslices 会将窗口划分为多个时片,根据 objective.timesliceTarget 将每个时片标记为良好或不良,再用良好时片数除以时片总数,因此每个时段的权重相同。低流量时段也很重要,或指标是聚合值的阈值而非可计数的良好/总量时,选择 timeslices。sli.metric.timeslice 要求 budgetingMethod: "timeslices"——二者必须配套使用,而且必须设置 objective.timesliceTarget 和 objective.timesliceWindow。

  7. 谨慎决定分组方式。 groupBy 会为每个唯一值创建一个独立的 SLO 实例,每个实例都有自己的转换分桶和告警。设置之前先衡量基数:

    FROM traces-*.otel-*
    | WHERE @timestamp >= NOW() - 24 hour
    | STATS instances = COUNT_DISTINCT(service.name)
    

    保留 @timestamp 时间范围限制。没有时间条件的基数聚合会扫描整个追踪数据流的保留数据;限定近期时间范围能以极低成本回答同一个问题。

    基数不是唯一需要检查的因素——该维度还必须有值。如果 groupBy 使用已映射但值为 null 的字段,就会生成一个涵盖所有数据的退化实例,看起来像是分组 SLO 正常运行,实际上并非如此。设置之前,使用 COUNT(<field>) 和 COUNT(*) 进行确认。

    使用 service.name、service.environment 或 k8s.namespace.name 等稳定且基数有限的维度进行分组。拒绝使用高基数字段——trace.id、url.full、user.id 以及 k8s.pod.name 这类不断变化的标识符;说明原因,而不是先创建 SLO、事后再发出警告。如果确实需要查看宽泛维度中各实体的情况,应筛选出相关实体,而不是对所有实体进行分组。Synthetics SLO 会按监控项和位置自动分组;请勿手动设置 groupBy。

  8. 创建并验证。 按照 references/slo-api-schemas.md 构建请求体,并调用 POST kbn:/api/observability/slos。随后使用 GET kbn:/api/observability/slos/{id} 读取并确认其正在计算后,再报告成功——已创建但转换尚未启动的 SLO 不会返回摘要数据。

在这里,KQL 是 API 契约,而非风格选择

Observability 的查询语言是 ES|QL;你为验证 SLI 而运行的所有探索性查询——包括基线、基数检查和流量分布查询——都必须使用 ES|QL 并通过 POST /_query 执行。

SLO 请求体中有一个例外。sli.kql.custom 的 good、total 和 filter 字段(以及其他指标类型的 filter 字段,还有 SLO 搜索中的 --kql-query 参数)都是 KQL 字符串,因为 SLO API 对这些字段有明确规定。这些字段没有 ES|QL 格式。仅在这些字段中使用 KQL:

{
  "type": "sli.kql.custom",
  "params": {
    "index": "traces-*.otel-*",
    "filter": "service.name : \"cart\" and kind : \"Server\"",
    "good": "http.response.status_code < 500",
    "total": "*",
    "timestampField": "@timestamp"
  }
}

不要将这些字段转换为 ES|QL——API 会拒绝请求或静默地错误解析。也不要将探索性查询转换为 KQL。

缺少字段时会发生什么

第 1 步坚持确认字段的原因是,这两种方言会以相反的方式失败,而危险的是最终进入 SLO 的那种方言。

探索性 ES|QL 查询会明确报错。将第 2 步的查询指向 logs-*.otel-* 时,由于不存在 http.response.status_code,会返回 HTTP 400:

line 3:49: Unknown column [http.response.status_code]

指标定义中的 KQL 完全不会报错。 对于未映射字段,KQL 会将数值比较编译为一个无法匹配任何内容的范围查询,而 SLO API 会毫无异议地接受该定义。在同一集群上,对 logs-*.otel-* 中的 101,920,257 个文档查询同一小时的时间窗口时,good 子句匹配了 0 个文档,而 total: "*" 匹配了 93,847 个文档。SLO 会正常计算,报告的 SLI 为 0%,未达到目标,并在首次转换运行时耗尽全部错误预算。接着添加下一节中的燃烧率规则,快速燃烧窗口就会针对一个什么都没测量的指标持续触发告警。

不要尝试改用 Lucene query_string 检查字段是否存在。同一个条件在该集群上用 Lucene 会返回 3,250 个匹配项——这不是因为字段存在,而是因为 Lucene 会对表达式进行分词,并将片段与默认字段进行全文匹配。Lucene 返回非零计数,并不能证明字段已映射。

请使用 GET /_field_caps 或 GET /<index>/_mapping 直接确认;还可以在 ES|QL 中使用 COUNT(<field>),进一步确认已映射的字段是否实际包含数据。

流程:在不增加噪声的前提下为 SLO 添加告警

创建 SLO 并不会自动创建任何告警。SLO API 绝不会自动创建燃烧率规则,必须另行通过 POST kbn:/api/alerting/rule/{id} 设置,规则类型为 slo.rules.burnRate。

  1. 使用严重程度不同的多个时间窗口。 燃烧率为 1 表示预算的消耗速度恰好会在窗口结束时耗尽预算。快速燃烧窗口(较长窗口约为 1 小时、短窗口为 5 分钟,燃烧率约为 14 倍)可以捕获故障,值得触发页面告警。慢速燃烧窗口(24 到 72 小时内约为 1 倍到 3 倍)可以捕获长期性能下降,应发送到工单队列。将所有窗口都路由到同一个页面告警连接器,是让 SLO 被忽视的最快方式。窗口值和操作组见 references/burn-rate-rules.md。

  2. 保留短窗口。 每个窗口都会将长窗口(燃烧率是否足以触发告警)与短窗口(问题是否仍在发生)配对。短窗口可以让已解决的事件自动停止触发告警,而不必由人手动静默。

  3. 移除重复覆盖。 如果燃烧率规则和原始阈值规则都监控同一信号,一起事件就会触发两次页面告警。添加任何规则前,请通过 GET kbn:/api/alerting/rules/_find 查找重叠项。保留燃烧率规则用于页面告警,并降级或删除原始阈值规则——但如果阈值规则覆盖了 SLO 在结构上无法检测到的无数据情况,那么这是真实的缺口,应予以保留。

  4. 安排静默,不要禁用。 若要在限定时间内暂停单条规则,请使用 POST kbn:/api/alerting/rule/{id}/_snooze_schedule;若要因计划变更暂停多条规则,请通过 POST kbn:/api/maintenance_window 设置维护窗口。两者都会自动过期。禁用规则会丢失其告警历史,还需要有人记得重新启用,因此 POST kbn:/api/alerting/rule/{id}/_disable 应仅用于错误的规则,而非暂时不便处理的规则。

  5. 进行可操作性测试。 规则正确触发,但响应人员无计可施,这属于缺陷,而非成功。请为每条规则明确值班人员要采取的第一步。如果坦诚的回答是“稍后再看”,那就不该触发页面告警——应将其移到慢速燃烧窗口或工单中,或者删除。

流程:通过合成监测器监控可用性

合成监测器会按计划从一个或多个位置探测端点,并将结果写入 synthetics-*。 它能回答“从外部来看,服务是否正常运行”,而服务自身发出的遥测数据永远无法回答这个问题。使用 GET kbn:/api/synthetics/monitors 和 POST kbn:/api/synthetics/monitors 管理监测器。

  1. 选择目标前,先规划检查预算。 可用性按检查次数而非请求次数衡量,因此检查频率决定了 SLI 的分辨率。以 10 分钟的频率持续 30 天,共有 4,320 次检查;如果目标为 99.99%,整个错误预算不到半次检查,因此一次短暂故障就会耗尽预算。要求预算至少能容纳 10 次检查——提高频率或降低目标,直到满足要求。

  2. 至少使用三个位置。 单位置监测器无法区分服务宕机和某个区域的网络路径异常。使用三个或更多位置后,这一判断会很明确,也能消除一大类误报。

  3. 将其接入 SLI。 使用 sli.synthetics.availability 创建 SLO,并按监测器 ID、项目或标签设置范围。将 groupBy 留空;该指标已经会为每个监测器和位置生成一个实例。

流程:运行与修复

  • 谨慎更新。 PUT kbn:/api/observability/slos/{id} 会重置底层转换,并从头重新计算历史数据。因此,更改目标或指标会丢弃现有的预算情况。在执行之前应说明这一点;如果旧历史仍然重要,优先创建第二个 SLO。
  • 卡住时重置。 POST kbn:/api/observability/slos/{id}/_reset 会重建转换和汇总数据。当 SLO 停止更新、索引映射发生变更,或升级导致定义过时时,请使用此操作——GET kbn:/api/observability/slos/_definitions 会报告哪些定义已过时。
  • 暂停还是退役。 POST kbn:/api/observability/slos/{id}/disable 会停止计算,但保留定义;POST kbn:/api/observability/slos/{id}/enable 会恢复计算。DELETE kbn:/api/observability/slos/{id} 是永久操作——请先与用户确认。
  • 检查集群配置。 每个 SLO 都由持续转换提供支持,因此集群需要同时承担 transform 和 ingest 角色的节点。如果 SLO 一直显示“无数据”,请先检查这一点,再排查指标。

示例

“为结账服务设置一个 SLO” — 解析 traces-*.otel-*,并确认 service.name 和 outcome 字段存在;使用 POST /_query 测量过去 30 天的成功率,然后推荐一种设计:如果测得的基线是 99.6%,则建议在 30 天滚动窗口上使用 sli.apm.transactionErrorRate,阈值设为 0.995,并采用 occurrences 预算方式;同时说明拒绝 99.9%,因为其 43 分钟的预算短于该服务观测到的月度降级时长。创建后读取以确认,然后单独创建消耗速率规则。

“我们想为 payments API 设置 99.99% 的 SLO” — 先测量。如果过去 30 天的基线是 99.7%,则直接拒绝 99.99%:它在 30 天内只允许 4 分 19 秒的预算,少于一次滚动部署所需的时间。建议当前设为 99.5%,并制定逐步提升计划,同时说明限制因素是部署流程,而不是目标值。

“当 p95 延迟超过 500 ms 时提醒我们” — 这是聚合值的阈值,因此应使用 sli.metric.timeslice 和百分位数指标,并设置 comparator: "LT"、threshold: 500;此外,该指标要求设置 budgetingMethod: "timeslices",并配置 timesliceTarget 和 timesliceWindow。先确认映射中的时长字段及其单位;如果用毫秒编写的阈值对应的是微秒字段,数值就会相差 1,000 倍。

“为每个 pod 创建一个 SLO,这样我们就能看出哪些 pod 不可靠” — 拒绝按此方式分组。k8s.pod.name 每次部署都会变化,因此每个 groupBy 值都会创建一个 SLO 实例,而该实例几天内就会成为孤立实例,但 transform 会永久保留其基数。建议改为按 k8s.namespace.name 或 service.name 分组,并指出,单个 pod 的可靠性问题是需要调查的症状,而不是应纳入预算的目标。

“日志节点上的磁盘一直在占满——能为此设置 SLO 吗?” — 不行。磁盘利用率有明确的安全上限,达到上限时也需要立即采取运维操作,因此应使用阈值规则,而不是可靠性目标。没有面向用户的结果可供预算,也没有合理的方式来定义磁盘空间耗尽 0.5% 的预算。

“我们的请求速率看起来不太对,但我们说不出具体阈值” — 没有固定界限,就无法设置 SLO 或阈值规则。应将其交给异常检测作业,该作业会学习季节性基线;同时说明,需要数周的历史数据,其评分才值得信赖。

“为什么每次结账事故都会让我们收到两次呼叫?” — 使用 GET kbn:/api/alerting/rules/_find 列出规则,检查同一信号上是否同时存在消耗速率规则和原始阈值规则。保留消耗速率规则作为呼叫通知,将阈值规则降级为工单,并确认没有将慢速消耗窗口路由到呼叫通知连接器。

指南

  • 在设计 SLO 之前先选择指标类型;容量上限属于阈值规则,无界信号则属于异常检测任务。
  • 在将字段写入指标之前,通过 GET /<index>/_mapping 或 GET /_field_caps 确认每个字段。切勿根据惯例推断字段名称。
  • 先通过 POST /_query 使用 ES|QL 验证 SLI;目标值应根据测得的基线设定,而非主观期望。
  • objective.target 是介于 0 和 1 之间的小数;99.5% 对应 0.995。
  • 时间切片指标需要设置 budgetingMethod: "timeslices"。
  • sli.kql.custom 的 good、total 和 filter 字段使用 KQL,因为 API 对这些字段有此规定。其他所有查询均使用 ES|QL。
  • 更新 SLO 会重置底层转换并重新计算历史数据;操作前请提醒用户。
  • 集群需要同时具有 transform 和 ingest 角色的节点。
  • SLO 卡住或索引映射发生更改后,请使用重置操作。
  • 按字段分组的 SLO 会为每个唯一值创建一个实例;对于高基数字段,应拒绝操作,而不是先创建再发出警告。
  • Synthetics SLO 会按监控器和位置自动分组;不要手动设置 groupBy。
  • SLO API 不会创建消耗率告警规则;请单独设置,并将快速消耗和缓慢消耗时间窗口路由到不同的严重级别。
  • 优先将规则设为暂停状态或开启维护窗口,而不是禁用规则。
  • 执行删除操作前请先确认。

操作

HTTP API(简写)elastic CLI 命令
POST /_queryelastic es esql query --format tsv --query '<esql>'
GET /_resolve/index/<pattern>elastic es indices resolve-index --name '<pattern>'
GET /<index>/_mappingelastic es indices get-mapping --index '<index>'
GET /_field_capselastic es field-caps --index '<index>' --fields '<fields>'
GET /_ml/anomaly_detectorselastic es ml get-jobs
GET kbn:/api/observability/sloselastic kb slo find-slos-op --space-id '<space>' --kql-query '<kql>'
POST kbn:/api/observability/sloselastic kb slo create-slo-op --space-id '<space>' --input-file <json>
GET kbn:/api/observability/slos/{id}elastic kb slo get-slo-op --space-id '<space>' --slo-id '<id>'
PUT kbn:/api/observability/slos/{id}elastic kb slo update-slo-op --space-id '<space>' --slo-id '<id>' --input-file <json>
DELETE kbn:/api/observability/slos/{id}elastic kb slo delete-slo-op --space-id '<space>' --slo-id '<id>'
POST kbn:/api/observability/slos/{id}/_resetelastic kb slo reset-slo-op --space-id '<space>' --slo-id '<id>'
POST kbn:/api/observability/slos/{id}/enableelastic kb slo enable-slo-op --space-id '<space>' --slo-id '<id>'
POST kbn:/api/observability/slos/{id}/disableelastic kb slo disable-slo-op --space-id '<space>' --slo-id '<id>'
GET kbn:/api/observability/slos/_definitionselastic kb slo get-definitions-op --space-id '<space>'
GET kbn:/api/alerting/rules/_findelastic kb alerting get-alerting-rules-find --filter '<kql>'
POST kbn:/api/alerting/rule/{id}elastic kb alerting post-alerting-rule-id --id '<id>' --input-file <json>
POST kbn:/api/alerting/rule/{id}/_snooze_scheduleelastic kb alerting post-alerting-rule-id-snooze-schedule --id '<id>' --input-file <json>
POST kbn:/api/alerting/rule/{id}/_disableelastic kb alerting post-alerting-rule-id-disable --id '<id>'
POST kbn:/api/maintenance_windowelastic kb maintenance-window post-maintenance-window --title '<title>' --input-file <json>
GET kbn:/api/synthetics/monitors无 CLI 绑定 — 请参阅下方的 CLI 缺口
POST kbn:/api/synthetics/monitors无 CLI 绑定 — 请参阅下方的 CLI 缺口
CLI 缺口。 截至 elastic CLI 0.2.0,尚未提供 Synthetics 监控管理 API 的绑定——stack kb
命名空间中没有 Synthetics 命令。上述 HTTP 简写仍是正确的契约且可移植,因此在描述必须执行的操作时仍应使用它,但不要编造 CLI 调用。请通过 Kibana 中的 Synthetics 应用、Synthetics 项目,或使用已持有凭据的工具直接调用 Kibana API 来创建和编辑监控。此技能中的其他所有内容,包括燃耗率规则和每项 SLO 操作,都有可用的 CLI 绑定。

评论

支持 Markdown