关于 observability-service-reliability
使用 Elastic 可观测性工具设计和运营服务可靠性目标的技能。它根据用户可感知的问题和数据选择合适的监测手段,并通过 Kibana 管理 SLO 和消耗速率告警。
主要功能
- 01在 SLO、规则、异常任务和合成监测间选择
- 02验证指标字段与实测历史
- 03设定 SLO 目标、窗口和预算方式
- 04创建和管理 SLO
- 05关联消耗速率告警规则
适用场景
- 01为用户可感知的结果定义 SLO
- 02为容量阈值选择监测方式
- 03为 SLO 添加消耗速率告警
- 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.mddocumentation.mdslo-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 都是乔装打扮的阈值规则。
-
明确用户可感知的症状。 询问用户或下游消费者会注意到什么,并因此提出投诉。如果答案是资源数值,而非使用体验——磁盘使用率达到 90%、堆内存持续增长、副本延迟——那么这是容量上限问题,不是可靠性目标。将其交给阈值规则处理。
-
检查是否已有覆盖。 使用
GET kbn:/api/observability/slos列出 SLO,使用GET kbn:/api/alerting/rules/_find列出告警规则,并使用GET /_ml/anomaly_detectors列出异常检测作业。在已覆盖的信号上再添加第二种工具,是产生重复告警的最常见原因。 -
选择工具。
问题 工具 原因及代价 想要按周预算的、用户可感知的成功率或延迟结果 SLO + 消耗速率规则 提供可消耗的预算和历史记录,并控制变更速度。代价是需要转换,需要稳定的流量,而且有意设计得较慢——即使是快速消耗,也使用一小时窗口。 有已知安全值且需要立即采取操作的硬性上限 阈值或自定义规则 在一个调度间隔内触发,无需转换。但它没有预算,也没有记忆,因此只要条件持续成立就会反复触发。 没有固定阈值、季节性强或涉及许多实体的信号 异常检测作业 可发现未知异常并适应季节性。需要数周历史数据才能可靠运行,并输出分数而非结果,因此不适合用于告警通知。 从自有遥测系统外部检查面向用户的端点是否可访问 Synthetics 监控 唯一能检测完全中断的工具。需要消耗检查预算(参见 Synthetics 部分),且无法解释内部的部分故障。 没有消费者契约的内部作业,或仍在每日变更的服务 无 没有负责人和稳定基线的 SLO 会一直显示为红色,最终被忽略,这比没有 SLO 更糟。 -
不要忽略中断情况。 基于服务自身日志或追踪构建的 SLI 无法检测服务消失:没有事件时就没有
total,因此比率未定义,SLO 既不会消耗预算,也不会恢复。对于面向用户的服务,每个基于请求的 SLO 都应配合 Synthetics 可用性监控或无数据阈值规则。这是同一信号使用两种工具是正确做法、而非重复覆盖的唯一情况。
流程:设计 SLO
-
定位数据并确认字段存在。 使用
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。请对照当前部署确认这两个字段,而不要盲目相信此列表。 -
先用 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"进行相同测量,结果如下:Service Server spans http.response.status_codecoverageevent.outcomecoveragecatalog 49,271 0% 100% gateway 37,773 100% 100% orders 37,754 100% 100% payments 34,710 100% 100% recommendations 34,692 0% 100% shipping 34,531 100% 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谓词,它会对整个跟踪数据流的保留期进行分桶:在演示集群上成本很低,在客户集群上则代价高昂。 -
根据数据形态选择 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。 -
设定可实现的目标。 取第 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 如果一次滚动部署、节点重启或依赖项短暂故障造成的损失就超过全部预算,那么这个目标便无法实现,应予以拒绝,而不是附带保留条件后接受。
-
选择时间窗口。
timeWindow.type为rolling(7d、30d、90d)或calendarAligned(1w、1M)。 滚动窗口会持续向前移动,因此预算会逐步恢复,消耗速率告警也能保持有效——这是所有运营场景的默认选择。日历对齐窗口会在周期边界重置,适合契约或月度报告的表述,但会在每月第一天造成预算断崖。用于分页告警时选择滚动窗口;只有在确实有人按日历周期报告时,才额外添加日历对齐 SLO。 -
选择预算计算方法。
occurrences会根据整个窗口内的总事件数计算良好事件所占比例,因此流量高峰时段的影响更大,而夜间的低流量故障几乎不会体现。timeslices会将窗口划分为多个时片,根据objective.timesliceTarget将每个时片标记为良好或不良,再用良好时片数除以时片总数,因此每个时段的权重相同。低流量时段也很重要,或指标是聚合值的阈值而非可计数的良好/总量时,选择timeslices。sli.metric.timeslice要求budgetingMethod: "timeslices"——二者必须配套使用,而且必须设置objective.timesliceTarget和objective.timesliceWindow。 -
谨慎决定分组方式。
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。 -
创建并验证。 按照 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 小时、短窗口为 5 分钟,燃烧率约为 14 倍)可以捕获故障,值得触发页面告警。慢速燃烧窗口(24 到 72 小时内约为 1 倍到 3 倍)可以捕获长期性能下降,应发送到工单队列。将所有窗口都路由到同一个页面告警连接器,是让 SLO 被忽视的最快方式。窗口值和操作组见 references/burn-rate-rules.md。
-
保留短窗口。 每个窗口都会将长窗口(燃烧率是否足以触发告警)与短窗口(问题是否仍在发生)配对。短窗口可以让已解决的事件自动停止触发告警,而不必由人手动静默。
-
移除重复覆盖。 如果燃烧率规则和原始阈值规则都监控同一信号,一起事件就会触发两次页面告警。添加任何规则前,请通过
GET kbn:/api/alerting/rules/_find查找重叠项。保留燃烧率规则用于页面告警,并降级或删除原始阈值规则——但如果阈值规则覆盖了 SLO 在结构上无法检测到的无数据情况,那么这是真实的缺口,应予以保留。 -
安排静默,不要禁用。 若要在限定时间内暂停单条规则,请使用
POST kbn:/api/alerting/rule/{id}/_snooze_schedule;若要因计划变更暂停多条规则,请通过POST kbn:/api/maintenance_window设置维护窗口。两者都会自动过期。禁用规则会丢失其告警历史,还需要有人记得重新启用,因此POST kbn:/api/alerting/rule/{id}/_disable应仅用于错误的规则,而非暂时不便处理的规则。 -
进行可操作性测试。 规则正确触发,但响应人员无计可施,这属于缺陷,而非成功。请为每条规则明确值班人员要采取的第一步。如果坦诚的回答是“稍后再看”,那就不该触发页面告警——应将其移到慢速燃烧窗口或工单中,或者删除。
流程:通过合成监测器监控可用性
合成监测器会按计划从一个或多个位置探测端点,并将结果写入 synthetics-*。
它能回答“从外部来看,服务是否正常运行”,而服务自身发出的遥测数据永远无法回答这个问题。使用 GET kbn:/api/synthetics/monitors 和 POST kbn:/api/synthetics/monitors 管理监测器。
-
选择目标前,先规划检查预算。 可用性按检查次数而非请求次数衡量,因此检查频率决定了 SLI 的分辨率。以 10 分钟的频率持续 30 天,共有 4,320 次检查;如果目标为 99.99%,整个错误预算不到半次检查,因此一次短暂故障就会耗尽预算。要求预算至少能容纳 10 次检查——提高频率或降低目标,直到满足要求。
-
至少使用三个位置。 单位置监测器无法区分服务宕机和某个区域的网络路径异常。使用三个或更多位置后,这一判断会很明确,也能消除一大类误报。
-
将其接入 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 /_query | elastic es esql query --format tsv --query '<esql>' |
GET /_resolve/index/<pattern> | elastic es indices resolve-index --name '<pattern>' |
GET /<index>/_mapping | elastic es indices get-mapping --index '<index>' |
GET /_field_caps | elastic es field-caps --index '<index>' --fields '<fields>' |
GET /_ml/anomaly_detectors | elastic es ml get-jobs |
GET kbn:/api/observability/slos | elastic kb slo find-slos-op --space-id '<space>' --kql-query '<kql>' |
POST kbn:/api/observability/slos | elastic 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}/_reset | elastic kb slo reset-slo-op --space-id '<space>' --slo-id '<id>' |
POST kbn:/api/observability/slos/{id}/enable | elastic kb slo enable-slo-op --space-id '<space>' --slo-id '<id>' |
POST kbn:/api/observability/slos/{id}/disable | elastic kb slo disable-slo-op --space-id '<space>' --slo-id '<id>' |
GET kbn:/api/observability/slos/_definitions | elastic kb slo get-definitions-op --space-id '<space>' |
GET kbn:/api/alerting/rules/_find | elastic 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_schedule | elastic kb alerting post-alerting-rule-id-snooze-schedule --id '<id>' --input-file <json> |
POST kbn:/api/alerting/rule/{id}/_disable | elastic kb alerting post-alerting-rule-id-disable --id '<id>' |
POST kbn:/api/maintenance_window | elastic 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 绑定。 |