Loki 关键指标监控指南:用高信号 PromQL 指标及早发现故障与性能劣化
【免费下载链接】lokiLike Prometheus, but for logs.项目地址: https://gitcode.com/GitHub_Trending/lok/loki
导读
Loki(仓库根目录,Like Prometheus, but for logs)的每个组件都会在/metrics端点暴露大量自身运行指标,但组件数量多、指标量大,逐一盯防既不现实也不高效。本文基于 docs/sources/operations/meta-monitoring/metrics.md 提炼出信号最强、最能提前发现负面趋势的一组"高信号指标",覆盖请求错误率、请求延迟、Panic、丢弃数据、Compaction 健康、Ingester 压力、Distributor 吞吐、对象存储、保留期清扫与 Loki Canary 端到端验证等场景。读完本文,你将掌握:每类异常对应哪个指标、用哪条 PromQL 查询、出现什么行为属于异常,以及 Loki mixin 内置的告警规则阈值;并能在事故响应时把指标与 Loki 组件源码 中指标的真实定义相互印证。
说明:本文所有示例查询均为 PromQL,需要在你存放 Loki 指标的 Prometheus 兼容数据源(如 Prometheus、Mimir、Grafana Cloud Metrics)上执行。
cluster、namespace、job这三个标签来自你的 Prometheus 抓取配置(例如 Kubernetes Monitoring Helm chart 添加的全局标签),并非 Loki 指标本身自带的标签。
指标从哪来:抓取与标签前提
Loki 各组件通过 Prometheus 客户端库注册指标,并经/metrics端点暴露。以 HTTP 请求级指标为例,Loki 复用了 dskit 的middleware.Instrument(见 vendor/github.com/grafana/dskit/middleware/instrument.go),该中间件对每个 HTTP 请求记录耗时直方图,并带上method、route、status_code、ws(是否为 WebSocket 握手请求)等标签——这正是后文loki_request_duration_seconds系列指标的来源。
- 抓取配置:确保 Prometheus 已抓取所有 Loki 组件 Pod/实例的
/metrics; - 标签前提:
cluster、namespace、job等标签由抓取端(如 Kubernetes Monitoring Helm chart 的全局标签与 relabel 规则)注入。如果你的部署使用不同的标签名,或未采集容器/节点指标,部分查询与告警会查不到数据,需要先做 relabel 对齐。
完整的采集与部署方案参见 Deploy Loki meta-monitoring 与 Install dashboards, alerts, and recording rules;mixin 编译产物(dashboards、alerts.yaml、rules.yaml)位于 production/loki-mixin-compiled,其源定义在 production/loki-mixin。
请求错误率(Request error rate)
优先看请求失败。5xx 响应的持续上升通常是最早的用户可见影响信号,先看它。
关键指标:
loki_request_duration_seconds:一个直方图,标签为method、route、status_code、ws。通过_count和_bucket后缀可以分别推导请求速率与延迟分位数。
示例查询——按路由统计 5xx 占比:
100 * sum(rate(loki_request_duration_seconds_count{status_code=~"5.."}[2m])) by (cluster, namespace, job, route) / sum(rate(loki_request_duration_seconds_count[2m])) by (cluster, namespace, job, route)异常行为:
- 任何 5xx 占比的持续上升;
- Loki mixin 的
LokiRequestErrors告警在该占比超过 10% 并持续 15 分钟后触发。其定义见 production/loki-mixin/alerts.libsonnet,表达式核心为100 * sum(rate(loki_request_duration_seconds_count{status_code=~"5.."}[2m])) by (cluster, job, route) / sum(rate(loki_request_duration_seconds_count[2m])) by (cluster, job, route) > 10,for: 15m,等级critical。
请求延迟 p99(Request latency)
延迟劣化往往先于硬性故障出现。读写路径的 p99 都应跟踪。
关键指标:
loki_request_duration_seconds_bucket:即上文指标直方图的桶,用于计算延迟分位数。
示例查询——全局 p99(含 tail、scheduler 等路由):
histogram_quantile(0.99, sum(rate(loki_request_duration_seconds_bucket[1m])) by (le, cluster, namespace, job, route))异常行为:
- p99 随时间持续上升,尤其是 query-frontend 和 distributor 路径;
- mixin 的
LokiRequestLatency告警在 p99 超过 1 秒并持续 15 分钟后触发。该告警排除了 tail 路由与 scheduler 路由(route!~"(?i).*tail.*|/schedulerpb.SchedulerForQuerier/QuerierLoop",见 alerts.libsonnet),因此上面的示例查询显示的 p99 可能比告警反应的阈值更高,属正常现象。
Panics(loki_panic_total)
Panic 是高严重性故障,应该始终保持为零。
关键指标:
loki_panic_total
示例查询:
sum(increase(loki_panic_total[10m])) by (cluster, namespace, job)异常行为:
- 任何大于零的值。mixin 的
LokiRequestPanics告警将其视为 critical(sum(increase(loki_panic_total[10m])) by (cluster, job) > 0)。
源码佐证:该指标定义在 pkg/util/server/recovery.go,是命名空间为loki的计数器。onPanic函数(同文件 L55-L62)会打印含多行堆栈的 panic 信息到 stderr,并调用panicTotal.Inc(),随后把请求转为 500 错误返回。恢复中间件同时覆盖了 HTTP(RecoveryHTTPMiddleware)、gRPC 流式与一元拦截器,以及查询范围中间件(RecoveryMiddleware)——也就是说,无论是 HTTP API、gRPC 还是查询范围处理链中的 panic,都会反映到该指标上。
被丢弃的数据(Discarded samples)
丢弃数据表示 Loki 拒绝或丢弃的日志,这是最重要的写入质量信号之一。
关键指标:
loki_discarded_samples_total:计数器,标签包括tenant、reason,以及retention_hours、policy、format。
示例查询——按租户与原因统计丢弃速率 Top10:
topk(10, sum by (tenant, reason) (rate(loki_discarded_samples_total{cluster="$cluster", namespace="$namespace"}[$__rate_interval])))异常行为:
- 丢弃速率上升;
- 出现新的或持续增长的
reason值(例如租户限流、流数限制)。
源码佐证:指标定义在 pkg/validation/validate.go,命名空间loki,标签为reason、tenant、retention_hours、policy、format;同文件还定义了loki_discarded_bytes_total。reason标签的取值(同文件 L17-L83)直接对应校验逻辑,排查时可根据原因精确定位:
- 限流类:
rate_limited(租户级摄入速率超限)、per_stream_rate_limit(单流速率超限)、blocked_ingestion/blocked_ingestion_policy(写入被策略阻断); - 流限制类:
stream_limit(活跃流数达到上限,通常需要减少标签基数或调高max_streams_per_user); - 时间戳类:
greater_than_max_sample_age(时间戳过旧,受reject_old_samples_max_age控制)、too_far_in_future(超出creation_grace_period)、too_far_behind(乱序写入时超出-ingester.max-chunk-age的一半); - 标签类:
max_label_names_per_series、label_name_too_long、label_value_too_long、duplicate_label_names、invalid_labels、missing_labels; - 结构化元数据类:
disallowed_structured_metadata、structured_metadata_too_large、structured_metadata_too_many; - 其他:
request_body_too_large、line_too_long(单条日志超长,受max_entry_size控制)、missing_enforced_labels等。
Compaction 健康
Compaction 问题会随时间推移静默劣化读性能与保留行为,且不易被直观发现。
注意:Compaction 与保留相关指标使用
loki_boltdb_shipper_前缀是历史原因。无论你使用哪种索引类型(包括 TSDB),compactor 都会发出这些指标。这从 pkg/compactor/metrics.go 可以确认——compact_tables_*系列指标的Namespace均为loki_boltdb_shipper。
关键指标:
loki_boltdb_shipper_compactor_running:当前实例上 compactor 是否在运行(值为 1 表示在运行);loki_boltdb_shipper_compact_tables_operation_last_successful_run_timestamp_seconds:最近一次成功 compaction 的 Unix 时间戳;loki_boltdb_shipper_compact_tables_operation_total:按status(success/failure)计数的 compaction 次数;loki_boltdb_shipper_compact_tables_operation_duration_seconds:完成全部表压缩所耗秒数。
示例查询——正在运行的 compactor 数量:
sum(loki_boltdb_shipper_compactor_running) by (cluster, namespace)示例查询——距上次成功 compaction 的时长(秒):
time() - (loki_boltdb_shipper_compact_tables_operation_last_successful_run_timestamp_seconds > 0)异常行为:
- 同时运行的 compactor 超过一个。同一时刻应只运行一个 compactor,多个并存可能导致数据丢失。mixin 的
LokiTooManyCompactorsRunning告警在超过一个 compactor 运行 5 分钟后触发(sum(loki_boltdb_shipper_compactor_running) by (cluster) > 1,for: 5m,等级 warning,见 alerts.libsonnet); - 数小时无成功 compaction。mixin 的
LokiCompactorHasNotSuccessfullyRunCompaction告警在最近一次成功运行距今超过 3 小时时开始计算,且该条件需持续 1 小时才触发,因此从异常发生到告警大约需要 4 小时(见 alerts.libsonnet)。告警同时覆盖"自启动以来从未成功运行"的场景(同文件 L96-L119)。
源码佐证:以上指标均在 pkg/compactor/metrics.go 中注册,其中compactorRunning的帮助文本明确"Value will be 1 if compactor is currently running on this instance";applyRetention*系列(loki_compactor_apply_retention_total、loki_compactor_apply_retention_duration_seconds、loki_compactor_apply_retention_last_successful_run_timestamp_seconds)也在同文件注册,供下文保留进度监控使用。
Ingester 健康与刷盘行为
Ingester 的压力往往表现为内存增长、chunk 利用率差或刷盘积压。
关键指标:
loki_ingester_memory_streams:每租户内存中的流数;loki_ingester_memory_stream_shards:内存中由 distributor 流分片(stream sharding)创建的流分片数,是loki_ingester_memory_streams的子集(携带__stream_shard__标签);loki_ingester_memory_chunks:内存中的 chunk 数;loki_ingester_flush_queue_length:刷盘队列长度;loki_ingester_chunk_utilization:chunk 利用率直方图;loki_ingester_chunks_flushed_total:已刷盘 chunk 数。
示例查询——内存流总数:
sum(loki_ingester_memory_streams{cluster="$cluster", namespace="$namespace"})示例查询——流分片所占比例(由 distributor 分片产生):
sum(loki_ingester_memory_stream_shards{cluster="$cluster", namespace="$namespace"}) / sum(loki_ingester_memory_streams{cluster="$cluster", namespace="$namespace"})示例查询——刷盘队列长度:
sum(loki_ingester_flush_queue_length{cluster="$cluster", namespace="$namespace"})异常行为:
- 内存流数或 chunk 数持续增长;
- 刷盘队列长度不断增加;
- chunk 利用率长期偏低。
源码佐证:loki_ingester_memory_streams与loki_ingester_memory_stream_shards定义在 pkg/ingester/instance.go,均为按tenant分组的 Gauge;loki_ingester_flush_queue_length等刷盘相关指标定义在 pkg/ingester/metrics.go(ingesterMetrics结构体中包含flushQueueLength、chunkUtilization、chunksFlushedPerReason等字段)。该文件还包含 WAL 相关指标(如loki_ingester_wal_disk_usage_percent、loki_ingester_wal_replay_active、loki_ingester_wal_discarded_samples_total),当怀疑磁盘或重启恢复问题时同样值得关注。
Distributor 吞吐
吞吐量变化有助于识别上游发送方问题、突发流量或写入瓶颈。
关键指标:
loki_distributor_bytes_received_total:每租户收到的未压缩字节数(含结构化元数据字节;对 OTLP 请求,resource 与 scope 属性每个请求只计一次);loki_distributor_lines_received_total:每租户收到的日志行数。
示例查询——字节接收速率:
sum(rate(loki_distributor_bytes_received_total{cluster="$cluster", namespace="$namespace"}[$__rate_interval]))示例查询——行数接收速率:
sum(rate(loki_distributor_lines_received_total{cluster="$cluster", namespace="$namespace"}[$__rate_interval]))异常行为:
- 急剧下降(可能是数据链路中断);
- 意外飙升(可能是过载或某个"吵闹"租户)。
源码佐证:两个指标定义在 pkg/loghttp/push/push.go。loki_distributor_bytes_received_total的标签为tenant、retention_hours、is_internal_stream、policy、format;loki_distributor_lines_received_total的标签为tenant、is_internal_stream、policy、format。同文件还提供了loki_distributor_expanded_bytes_received_total、loki_distributor_structured_metadata_bytes_received_total等更细粒度的指标,可在需要区分结构化元数据占比时使用。
对象存储操作
对象存储的延迟与失败直接影响查询与保留流程。
关键指标:
loki_objstore_bucket_operations_total:对 bucket 的所有尝试操作总数(按operation与bucket标签分组);loki_objstore_bucket_operation_failures_total:失败操作数("预期内"的失败不计入);loki_objstore_bucket_operation_duration_seconds:成功操作耗时直方图(iter 操作包含每次回调耗时)。
示例查询——按操作类型统计失败速率:
sum by (operation) (rate(loki_objstore_bucket_operation_failures_total{cluster="$cluster", namespace="$namespace"}[$__rate_interval]))示例查询——操作延迟 p99:
histogram_quantile(0.99, sum(rate(loki_objstore_bucket_operation_duration_seconds_bucket{cluster="$cluster", namespace="$namespace"}[$__rate_interval])) by (le, operation))异常行为:
- 各操作类型的失败率上升;
get、get_range或upload的 p99 延迟持续升高。
源码佐证:该系列指标来自 Loki 依赖的对象存储库 thanos-objstore 的BucketMetrics(见 vendor/github.com/thanos-io/objstore/objstore.go):objstore_bucket_operations_total与objstore_bucket_operation_failures_total为计数器,objstore_bucket_operation_duration_seconds为直方图,均带常量标签bucket与动态标签operation。另通过IsOpFailureExpectedFunc(同文件 L493-L494)机制,调用方可以把部分可预期的错误(如文件不存在)排除在失败计数之外,因此失败指标的上升更有排查价值。
资源与运行时健康
资源压力可以在告警阈值被击穿之前就解释或预示服务劣化。
常见跟踪信号:
- 容器 CPU 使用率;
- 容器内存工作集(memory working set);
- Go 堆使用量;
- 磁盘读写速率;
- 容器重启次数。
异常行为:
- 反复出现重启尖峰;
- CPU 持续饱和;
- 内存只涨不回收。
这些信号通常来自 Kubernetes 监控栈(cAdvisor、kube-state-metrics、Node Exporter 采集的容器/节点指标),而非 Loki 自身暴露,因此需要在抓取端保证已采集容器与节点指标(参见 mixins.md 中关于标签前提的说明)。
Loki Canary(端到端数据验证)
如果你运行了 Loki Canary,请把它当作端到端正确性信号,而不只是性能信号。Canary 会持续写入带唯一标识的日志并回查,用于验证日志"写入-存储-查询"全链路是否正确。
关键指标:
loki_canary_missing_entries_total:在maxWait时间内既未通过 WebSocket 也未通过直接查询收到的日志条目数;loki_canary_spot_check_missing_entries_total:spot check(抽查式直接查询)中未收到的条目数;loki_canary_response_latency_seconds_bucket:响应延迟直方图。
示例查询——缺失率(百分比):
sum(increase(loki_canary_missing_entries_total{cluster=~"$cluster", namespace=~"$namespace"}[$__range])) / sum(increase(loki_canary_entries_total{cluster=~"$cluster", namespace=~"$namespace"}[$__range])) * 100异常行为:
- 任何非零缺失率持续存在。
源码佐证:Canary 指标定义在 pkg/canary/comparator/comparator.go:loki_canary_entries_total统计写入文件的日志条目总数,loki_canary_missing_entries_total统计超过maxWait未收到的条目,loki_canary_spot_check_missing_entries_total统计抽查未命中条目,另有loki_canary_websocket_missing_entries_total(仅 WebSocket 通道超时未收到)、loki_canary_unexpected_entries_total(收到未预期条目)等。除以总数得到的缺失率是判断全链路丢数据的直接依据。
内部错误日志速率(Internal error log rate)
内部日志在指标显示劣化时能提供快速上下文。
关键指标:
loki_internal_log_messages_total:Loki 自身产生的日志消息总数(按level标签分组)。
使用方式:将该指标与组件日志配合,用于定位故障从何处开始。
源码佐证:该指标在 pkg/util/log/log.go 的newPrometheusLogger中注册,是按level分组的计数器,覆盖 debug/info/warn/error 等各级别;同文件还注册了loki_internal_log_flushes直方图,反映行缓冲日志器的刷盘行为。另外 Loki 默认使用带缓冲的日志器(内存缓冲 256 行、10MB,100ms 强制刷盘),监控该指标可以观察到错误日志是否在短时间内激增。
保留与清扫进度(Retention and sweeper progress)
保留与清扫(sweeper)滞后会导致存储增长以及数据生命周期动作延迟。
关键指标:
loki_compactor_apply_retention_last_successful_run_timestamp_seconds:最近一次成功执行保留操作的 Unix 时间戳;loki_boltdb_shipper_retention_sweeper_marker_file_processing_current_time:当前正在处理的标记文件(marker file)的创建时间;loki_boltdb_shipper_retention_sweeper_chunk_deleted_duration_seconds_count:删除 chunk 耗时直方图的计数(按status分组)。
示例查询——清扫器滞后时间(秒):
time() - (loki_boltdb_shipper_retention_sweeper_marker_file_processing_current_time{cluster="$cluster", namespace="$namespace"} > 0)异常行为:
- 清扫器滞后持续增大;
- 删除吞吐下降或持续删除失败。
源码佐证:loki_compactor_apply_retention_*系列在 pkg/compactor/metrics.go 注册(命名空间loki_compactor);清扫器相关指标在 pkg/compactor/retention/metrics.go 注册,其中retention_sweeper_marker_file_processing_current_time帮助文本为"The current time of creation of the marker file being processed"——当它长时间不前进时即表示清扫停滞。同文件还包含loki_boltdb_shipper_retention_marker_files_current、loki_boltdb_shipper_retention_marker_files_deleted_total、loki_boltdb_shipper_retention_marker_table_processed_total等指标,可用于观察标记文件的积压与删除进度。loki_compactor_retention_chunks_expired_by_ingestion_time_total(同文件 L55-L63)则反映按摄入时间(而非数据时间范围)过期删除的 chunk 数。
告警落地:结合 Loki mixin
上述各节的异常阈值并非凭空而来,Loki 官方 mixin 已将其中最关键的部分固化为告警规则,源定义集中在 production/loki-mixin/alerts.libsonnet,编译产物为 production/loki-mixin-compiled/alerts.yaml(告警)与 production/loki-mixin-compiled/rules.yaml(录制规则,部分仪表盘面板依赖它才有数据)。本文涉及的告警速查:
| 告警名 | 触发条件 | 持续时间 | 等级 |
|---|---|---|---|
LokiRequestErrors | 5xx 占比 > 10% | 15m | critical |
LokiRequestLatency | p99 > 1s(排除 tail 与 scheduler 路由) | 15m | critical |
LokiRequestPanics | loki_panic_total10 分钟增量 > 0 | 立即 | critical |
LokiTooManyCompactorsRunning | compactor 运行数 > 1 | 5m | warning |
LokiCompactorHasNotSuccessfullyRunCompaction | 距上次成功 compaction 超过 3h(或启动后从未成功),再持续 1h | 合计约 4h | critical |
安装方式:将 production/loki-mixin-compiled/dashboards 下的仪表盘导入 Grafana,再用mimirtool rules load rules.yaml(必需)与mimirtool rules load alerts.yaml(可选)把规则加载到 Prometheus/Mimir。完整步骤见 Install dashboards, alerts, and recording rules。
下一步建议
- 安装并持续更新最新版 Loki mixin 仪表盘与告警,升级 Loki 时同步复查 mixin 版本;
- 在本文这些基线信号之上,针对你自己的组件拓扑补充定制告警(例如按租户的丢弃速率、对象存储单 bucket 失败率);
- 事故响应时,把指标与 Loki 组件日志(例如 pkg/util/log/log.go 的
loki_internal_log_messages_total)以及 metrics.go 等源码中定义的指标原始 Help 文本相互对照,快速定位故障起点。
【免费下载链接】lokiLike Prometheus, but for logs.项目地址: https://gitcode.com/GitHub_Trending/lok/loki
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考