菜单
开源 RSS

Grafana Mimir 运行手册

本文档包含运行手册,或至少是一个检查清单,用于处理 mimir-mixin 中的警报和 Mimir 的日志。本文档假设您正在运行一个 Mimir 集群

  1. 使用此 mixin 配置
  2. 使用 GCS 作为对象存储(但也适用于其他后端)

警报

MimirIngesterRestarts

首先,检查警报是针对单个 ingester 还是多个。即使警报只针对一个 ingester,最好还是每隔几分钟检查一次 kubectl get pods --namespace=<prod/staging/etc.>,或查看查询 rate(kube_pod_container_status_restarts_total{container="ingester"}[30m]) > 0,直到确定没有导致多个重启的更大问题为止。

接下来,检查 kubectl get events,可以带或不带 --namespace 标志,以查找节点重启或其他相关问题。这里可以使用 Grep 或类似工具来过滤输出。此警报最常见的原因是单个云提供商节点重启,导致该节点上的 ingester 被重新调度到其他地方。

在事件中,您需要查找如下信息

57m Normal NodeControllerEviction Pod Marking for deletion Pod ingester-01 from Node cloud-provider-node-01
37m Normal SuccessfulDelete ReplicaSet (combined from similar events): Deleted pod: ingester-01
32m         Normal    NodeNotReady              Node   Node cloud-provider-node-01 status is now: NodeNotReady
28m         Normal    DeletingAllPods           Node   Node cloud-provider-node-01 event: Deleting all Pods from Node cloud-provider-node-01.

如果从上述信息中找不到明显原因,请检查负载是否增加

  • 如果活动时间序列数量增加且分配的内存不足,请水平扩展 ingester,以使每个 ingester 的时间序列数量与之前相同。
  • 如果发生中断,Mimir 恢复正常后,入站流量增加。(或者) Prometheus remote-write 客户端滞后,开始以更高的速率发送样本(同样是流量增加,但体现在样本数量上)。在这种情况下,也请水平扩展 ingester。

MimirIngesterReachingSeriesLimit

当启用每个 ingester 实例的 max_series 限制且 ingester 中的实际内存中时间序列数量接近限制时,会触发此警报。阈值设置为 80%,以便在达到限制之前有机会做出反应。达到限制后,向 ingester 写入新时间序列的请求将失败。向现有时间序列追加样本会继续成功。

请注意,返回给发送方的错误响应被归类为“服务器错误”(5xx),发送方应该会重试。在这种情况下,这些重试会阻塞数据流,并且新数据会在发送方排队。如果在短时间内清除此状况,服务可以恢复且不会丢失数据。

这与超出 max_global_series_per_user 限制时的情况不同,超出该限制被视为“客户端错误”(4xx)。在这种情况下,多余的数据会被丢弃。

紧急情况下

  • 如果实际时间序列数量非常接近或已达到限制,您可以通过运行时配置增加限制以争取一些时间
  • 增加限制会增加 ingester 的内存利用率。请通过 Mimir / Writes Resources 仪表盘监控 ingester 的内存利用率

如何配置限制

  • 该限制可以在 CLI (-ingester.instance-limits.max-series) 或运行时配置中配置
    ingester_limits:
      max_series: <int>
  • mixin 在运行时配置中配置限制,可以通过以下方式微调
    _config+:: {
      ingester_instance_limits+:: {
        max_series: <int>
      }
    }
  • 在运行时配置中配置后,更改会即时生效,无需重启 ingester
  • 可以通过 cortex_ingester_instance_limits{limit="max_series"} 查询配置的限制

如何解决

  1. 暂时增加限制
    如果实际时间序列数量非常接近或已达到限制,或者您预计 ingester 在扩容导致陈旧时间序列被丢弃之前就会达到限制,则也应该暂时增加限制。
  2. 检查 shuffle-sharding 分片大小是否正确
  • 启用 shuffle-sharding 时,我们假定租户平均使用其最大时间序列限制的 50%,目标是每个租户/每个 ingester 最多处理 10 万个时间序列。

  • 运行以下即时查询以找到可能给 ingester 带来更大压力的租户。该查询排除了已在所有 ingester 上进行分片的租户

    topk by (pod) (5, # top 5 tenants per ingester
        sum by (user, pod) ( # get in-memory series for each tenant on each pod
            cortex_ingester_memory_series_created_total{namespace="<namespace>"} - cortex_ingester_memory_series_removed_total{namespace="<namespace>"}
        )
        and on(user) # intersection with tenants that are exceeding 50% of their series limit (added across ingesters & accounting for replication)
        (
            sum by (user) ( # total in-memory series for the tenant across ingesters
                cortex_ingester_memory_series_created_total{namespace="<namespace>"} - cortex_ingester_memory_series_removed_total{namespace="<namespace>"}
            )
            /
            scalar( # Account for replication
                ( # Classic storage
                    max(cortex_distributor_replication_factor{namespace="<namespace>"})
                )
                or
                ( # Ingest storage
                    # count the number of zones processing writes
                    count(group by (job) (cortex_ingester_memory_series{namespace="<namespace>"}))
                )
            )
            > 70000 # show only big tenants - with more than 70K series before replication
            > 0.5 * max by(user) (cortex_limits_overrides{namespace="<namespace>", limit_name="max_global_series_per_user"}) # global limit
        )
        and on (pod) ( # intersection with top 3 ingesters by in-memory series
            topk(3,
                sum by (pod) (cortex_ingester_memory_series{namespace="<namespace>"})
            )
        )
        and on(user) ( # intersection with the tenants which don't have series on all ingesters
            count by (user) (cortex_ingester_memory_series_created_total{namespace="<namespace>"}) # count ingesters where each tenant has series
            !=
            scalar(count(count by (pod) (cortex_ingester_memory_series{namespace="<namespace>"}))) # count total ingesters: first `count` counts series by ingester (we ignore the counted number), second `count` counts rows in series per ingester, second count gives the number of ingesters
        )
    )
  • 检查输出中每个租户当前的 分片大小,如果它们尚未在所有 ingester 上进行分片,您可以考虑将其分片大小翻倍

  • 请注意,当增加租户的分片大小时,内存中的时间序列数量会暂时增加。请务必监控

    • 每个 ingester 的时间序列数量,确保没有接近限制。您可能需要暂时提高 ingester 的 max_series
    • 每个租户的时间序列数量。由于重新分片,时间序列会被多次计数(在新旧 ingester 中),因此租户可能会因达到 per_user 时间序列限制而导致样本被拒绝。您可能需要暂时提高该限制。
  • 受影响租户的分片大小增加后,至少 1 小时后发生的 TSDB head 压缩将有效减少 ingester 中的内存中时间序列数量

  1. 扩展 ingester
    扩展 ingester 将降低每个 ingester 的时间序列数量。然而,此更改的效果最多需要 4 小时才能显现,因为扩容后需要等待 TSDB head 压缩将所有陈旧时间序列从内存中丢弃,这最多可能需要 4 小时(使用默认配置,TSDB 会保留内存中长达 3 小时的时间序列,并且每 2 小时进行一次压缩)。

MimirIngesterReachingTenantsLimit

当启用每个 ingester 实例的 max_tenants 限制且 ingester 中的实际租户数量接近限制时,会触发此警报。达到限制后,向 ingester 写入新租户的请求将失败 (5xx),而对先前存在的租户的请求将继续成功。

ingester 中每个租户的内存利用率包括 TSDB stripes 和 chunk writer buffers 的分配开销。如果租户数量很高,这可能会显著影响 ingester 的总内存利用率。这些分配的大小分别由 -blocks-storage.tsdb.stripe-size(默认 16KiB)和 -blocks-storage.tsdb.head-chunks-write-buffer-size-bytes(默认 4MiB)控制。

紧急情况下

  • 如果实际租户数量非常接近或已达到限制,您可以通过运行时配置增加限制以争取一些时间
  • 增加限制会增加 ingester 的内存利用率。请通过 Mimir / Writes Resources 仪表盘监控 ingester 的内存利用率

如何配置限制

  • 该限制可以在 CLI (-ingester.instance-limits.max-tenants) 或运行时配置中配置
    ingester_limits:
      max_tenants: <int>
  • mixin 在运行时配置中配置限制,可以通过以下方式微调
    _config+:: {
      ingester_instance_limits+:: {
        max_tenants: <int>
      }
    }
  • 在运行时配置中配置后,更改会即时生效,无需重启 ingester
  • 可以通过 cortex_ingester_instance_limits{limit="max_tenants"} 查询配置的限制

如何解决

  1. 确保在 Mimir 集群中启用 shuffle-sharding
  2. 假设启用了 shuffle-sharding,扩展 ingester 将降低每个 ingester 的租户数量。但是,此更改的效果仅在 -blocks-storage.tsdb.close-idle-tsdb-timeout 周期后才可见,因此您可能需要暂时增加限制

MimirDistributorGcUsesTooMuchCpu

当 distributor 花费过多 CPU 时间进行垃圾回收时,会触发此警报。这是设置 GOMEMLIMIT 过低的症状,导致 GC 触发过于频繁。

如何解决

  1. 确保 distributor 水平 pod 自动伸缩正常工作,以便 distributor 能够响应 CPU 压力进行水平扩展。

MimirDistributorReachingInflightPushRequestLimit

当启用每个 distributor 实例的 cortex_distributor_inflight_push_requests 限制且实际进行中的推送请求数量接近设定的限制时,会触发此警报。一旦达到限制,向 distributor 推送新请求将失败 (5xx),而现有进行中的推送请求将继续成功。

紧急情况下

  • 如果实际进行中的推送请求数量非常接近或已达到设定的限制,您可以通过 CLI 标志或配置增加限制以争取一些时间
  • 增加限制会增加进行中的推送请求数量,这将增加 distributor 的内存利用率。请通过 Mimir / Writes Resources 仪表盘监控 distributor 的内存利用率

如何配置限制

  • 该限制可以通过 CLI 标志 (-distributor.instance-limits.max-inflight-push-requests) 或在配置中配置
    distributor:
      instance_limits:
        max_inflight_push_requests: <int>
  • 这些更改需要重启 distributor 才能生效。
  • 可以通过 cortex_distributor_instance_limits{limit="max_inflight_push_requests"}) 查询配置的限制

如何解决

  1. 暂时增加限制
    如果实际进行中的推送请求数量非常接近或已达到限制。
  2. 扩展 distributor
    扩展 distributor 将降低每个 distributor 的进行中的推送请求数量。

MimirRequestLatency

当特定 Mimir 路由遇到高延迟时,会触发此警报。

警报消息包含遇到高延迟的 Mimir 服务和路由。根据这些信息判断警报是关于读取路径还是写入路径(请参阅按路径划分的 Mimir 路由)。

写入延迟

如何调查

  • 检查 Mimir / Writes 仪表盘
    • 查看仪表盘,您应该能看到高延迟源自哪个 Mimir 服务
    • 仪表盘中的面板按网络路径垂直排序(例如,gateway -> distributor -> ingester)。使用ingest-storage时,网络路径变为 gateway -> distributor -> Kafka。
  • 推断延迟是在堆栈的哪个位置引入的
    • gateway
      • 延迟可能是由 gateway 接收整个客户端请求所需的时间造成的。发生这种情况的原因有很多,因此可能需要与用户沟通。例如
        • 客户端和 gateway 之间的网络问题,例如丢包。
        • 中间网络跳点(如负载均衡器或 HTTP 代理)性能低下。
        • 客户端进程 CPU 资源不足。
      • 可能需要扩展 gateway。使用 Mimir / Scaling 仪表盘检查 CPU 使用率与请求量的对比。
      • 认证可能存在问题(例如,auth 层运行缓慢)
    • distributor
      • 通常,distributor 的 p99 延迟在 50-100ms 范围内。如果 distributor 延迟高于此范围,您可能需要扩展 distributor。
      • 使用 Mimir ingest-storage 时,distributor 将请求写入 Kafka 兼容后端。distributor 延迟增加也可能源自此后端。
    • ingester
      • 通常,ingester 的 p99 延迟在 5-50ms 范围内。如果 ingester 延迟高于此范围,您应该在扩展 ingester 之前调查根本原因。
      • 检查以下警报,如果触发,请解决
        • MimirIngesterReachingSeriesLimit
        • MimirProvisioningTooManyWrites

读取延迟

查询性能是一个已知问题。查询可能因高基数、大时间范围和/或未利用缓存(例如,查询尚未缓存的时间序列数据)而变慢。调查此警报时,您应检查它是否由少数慢查询引起,或者是否存在需要修复的操作/配置问题。

如何调查

  • 检查 Mimir / Reads 仪表盘
    • 查看仪表盘,您应该能看到高延迟源自哪个 Mimir 服务
    • 仪表盘中的面板按网络路径垂直排序(例如,gateway -> query-frontend -> query-scheduler -> querier -> store-gateway)
  • 检查 Mimir / Slow Queries 仪表盘,查看是否由少数慢查询引起
  • 推断延迟是在堆栈的哪个位置引入的
    • gateway
      • 可能需要扩展 gateway。使用 Mimir / Scaling 仪表盘检查 CPU 使用率与请求量的对比。
      • 认证可能存在问题(例如,auth 层运行缓慢)
    • query-frontend
      • 可能需要扩展 query-frontend。如果 Mimir 集群运行了 query-scheduler,则可以无副作用地扩展 query-frontend,否则 query-frontend 的最大副本数应为配置的 -querier.max-concurrent
    • querier
      • 查看慢查询追踪信息,找到延迟所在。
      • 通常,慢查询要么源自运行 PromQL 引擎(innerEval),要么源自从 ingester 和/或 store-gateway 获取数据块(chunk)。
      • 如果慢查询源自运行 PromQL 引擎,通常我们能做的很少。只有当 querier 节点过载时,扩展 querier 才可能有帮助。
      • 如果慢查询源自从 ingester 和/或 store-gateway 获取数据块,您应该深入调查根本原因。常见原因包括
        • ingester CPU 利用率高
          • 扩展 ingester
        • store-gateway 缓存命中率低
          • 检查 Memcached Overview 仪表盘
          • 如果 memcached 逐出率很高,那么您应该扩展 memcached 副本。检查 Mimir / Scaling 仪表盘的建议,并根据需要进行合理调整。
          • 如果 memcached 逐出率为零或非常低,则可能是由“首次”查询引起的
        • 缓存查询超时
          • 检查 store-gateway 日志,查找有关 Memcached 查询超时的警告(示例查询:{namespace="example-mimir-cluster", name=~"store-gateway.*"} |= "level=warn" |= "memcached" |= "timeout"
          • 如果确实有很多 Memcached 查询超时,请考虑 store-gateway Memcached 超时设置 (-blocks-storage.bucket-store.chunks-cache.memcached.timeout) 是否足够
      • 通过查阅 Mimir / Queries 仪表盘的“队列长度”面板,确定查询是否因 querier 繁忙而排队等待(迹象是队列长度在一段时间内 > 0)
        • 如果查询正在排队等待
          • 如果 querier 没有自动伸缩,考虑增加 querier 数量;如果已自动伸缩,请检查自动伸缩参数
        • 如果查询未在排队等待
          • 如果尚未启用,考虑启用查询分片,以增加查询并行度
          • 如果已启用查询分片,考虑增加提交慢查询的租户的总查询分片数量 (query_sharding_total_shards),以便其查询可以进一步并行化
    • ingester
      • 检查 ingester 是否过载。如果是且您可以垂直扩展 ingester,那可能是最佳操作。如果不可能,水平扩展也有帮助,但 ingester 完全重新分布其时间序列可能需要数小时。
      • 使用 ingest-storage 时,检查使用强一致性的查询比例,以及使用强一致性的查询延迟。

Alertmanager

如何调查

  • 检查 Mimir / Alertmanager 仪表盘
    • 查看仪表盘,您应该能看到堆栈的哪个部分受到了影响
  • 推断延迟是在堆栈的哪个位置引入的
    • 配置 API (gateway) + Alertmanager UI
      • 延迟可能是由 gateway 接收整个客户端请求所需的时间造成的。发生这种情况的原因有很多,因此可能需要与用户沟通。例如
        • 客户端和 gateway 之间的网络问题,例如丢包。
        • 中间网络跳点(如负载均衡器或 HTTP 代理)性能低下。
        • 客户端进程 CPU 资源不足。
      • 可能需要扩展 gateway。使用 Mimir / Scaling 仪表盘检查 CPU 使用率与请求量的对比。
      • 认证可能存在问题(例如,auth 层运行缓慢)
    • Alertmanager distributor
      • 通常,Alertmanager distributor 的 p99 延迟在 50-100ms 范围内。如果 distributor 延迟高于此范围,您可能需要增加 alertmanager 副本数量。

MimirRequestErrors

当特定路由的 5xx 错误率在一段时间内 > 1% 时,会触发此警报。

此警报通常是检测问题/中断的最后一道防线。SLO 警报预计会更早触发:如果同一读/写路径也触发了 SLO 警报,则您可以忽略此警报,重点关注 SLO 警报(但调查程序通常是相同的)。

如何调查

  • 检查是哪个路由触发了警报(请参阅按路径划分的 Mimir 路由
    • 写入路径:打开 Mimir / Writes 仪表盘
    • 读取路径:打开 Mimir / Reads 仪表盘
  • 查看仪表盘,您应该能看到错误源自哪个 Mimir 服务
    • 仪表盘中的面板按网络路径垂直排序(例如,写入路径:gateway -> distributor -> ingester)
  • 如果失败的服务发生 OOM(OOMKilled):扩容或增加内存
  • 如果失败的服务崩溃/发生 panic:在日志中查找堆栈跟踪信息,并从那里开始调查
    • 如果崩溃的服务是 query-frontend、querier 或 store-gateway,并且您启用了“活动跟踪器”功能,请在日志文件中查找 found unfinished activities from previous run 消息以及随后的 activity 消息,查看是哪些查询导致了崩溃。
  • 使用 Memberlist 作为哈希环的 KV 存储时,确保 Memberlist 正常工作。请参阅 MimirGossipMembersTooHighMimirGossipMembersTooLow 警报的说明。
  • 使用 ingest-storage 且 distributor 无法将请求写入 Kafka 时,确保 Kafka 正常运行。

Alertmanager

如何调查

  • 查看 Mimir / Alertmanager 仪表盘,您应该能看到错误源自堆栈的哪个部分
  • 如果某些副本发生 OOM(OOMKilled):扩容或增加内存
  • 如果失败的服务崩溃/发生 panic:在日志中查找堆栈跟踪信息,并从那里开始调查
  • 如果 route 标签是 alertmanager,请检查日志中包含 component=AlertmanagerDistributor 的 distributor 错误
    • 使用 Mimir / Alertmanager resources 仪表盘检查实例是否资源不足
    • 如果 distributor 错误是 context deadline exceeded 且实例资源充足,请使用 -alertmanager.alertmanager-client.remote-timeout=<timeout> 增加 distributor 超时时间。如果未指定,默认值为 2 秒。

MimirIngesterUnhealthy

当一个或多个 ingester 被标记为不健康时,会触发此警报。检查 ring 网页,查看哪些被标记为不健康。然后您可以查看日志,看是否有与相关 ingester 相关的信息,例如 kubectl logs --follow ingester-01 --namespace=prod。一个简单的解决方法可能是在 ring 页面上选择Forget,特别是当 Pod 不再存在时。它可能不存在了是因为它所在的节点已关闭。检查是否有与该 Pod 所在或曾经所在的节点相关的日志,例如 kubectl get events --namespace=prod | grep cloud-provider-node

MimirMemoryMapAreasTooHigh

当 Mimir 进程的内存映射区域数量接近限制时,会触发此警报。该限制是内核施加的每个进程的限制,此问题通常由大量 mmap 失败引起。

如何解决

  • 增加系统限制:sysctl --write vm.max_map_count=<NEW LIMIT>
  • 如果是由 store-gateway 引起,考虑启用 -blocks-storage.bucket-store.index-header.lazy-loading-enabled=true 以在查询时延迟 mmap index-headers

更多信息

MimirRulerFailedRingCheck

当 ruler 无法验证是否应拥有某个规则组的评估权时,会触发此警报。最可能的原因是某个规则 ring 条目不健康。如果是这种情况,请前往 ring 管理 http 页面并忘记不健康的 ruler。另一个可能的原因是 ring 客户端返回错误。如果是这种情况,请根据正在使用的后端实现来调试 ring。

使用 Memberlist 作为哈希环的 KV 存储时,确保 Memberlist 正常工作。请参阅 MimirGossipMembersTooHighMimirGossipMembersTooLow 警报的说明。

MimirRulerTooManyFailedPushes

当 ruler 无法将新样本(规则评估结果)推送到 ingester 时,会触发此警报。

通常,推送样本失败可能由于 Mimir 操作问题(例如,太多 ingester 崩溃,ruler 无法向其写入样本),或由于结果数据问题(例如,用户达到时间序列数量限制、乱序样本等)。此警报仅针对第一类问题触发,不针对由限制或无效规则引起的问题。

如何解决

  • 查看 ruler 日志以找出 ruler 无法写入样本的原因。请注意,ruler 会记录所有推送错误,包括“用户错误”,但这些不会触发警报。重点关注 ingester 的问题。
  • 使用 Memberlist 作为哈希环的 KV 存储时,确保 Memberlist 正常工作。请参阅 MimirGossipMembersTooHighMimirGossipMembersTooLow 警报的说明。

MimirRulerTooManyFailedQueries

当 ruler 无法评估规则查询时,会触发此警报。

每个规则评估可能因多种原因而失败,例如,无效的 PromQL 表达式,或查询达到数据块数量限制。这些是“用户错误”,此警报会忽略它们。

有一类错误更为重要:由于无法从 store-gateway 或 ingester 读取数据而导致的错误。这些错误在从 querier 运行时会返回 500。如果此类失败过多,则会触发此警报。

如何解决

  • 查看 ruler 日志以找出 ruler 无法评估查询的原因。请注意,ruler 会记录规则评估错误,即使是“用户错误”也会记录,但这些不会触发警报。重点关注 ingester 或 store-gateway 的问题。
  • 如果启用了远程操作模式,问题可能出在 ruler 查询路径的任何组件上(ruler-query-frontend、ruler-query-scheduler 和 ruler-querier)。检查 Mimir / Remote ruler readsMimir / Remote ruler reads resources 仪表盘,找出错误源自哪个 Mimir 服务。
    • 如果 ruler 日志记录了 gRPC 错误“received message larger than max”,考虑在 ruler 中增加 -ruler.query-frontend.grpc-client-config.grpc-max-recv-msg-size。此配置选项设置 ruler 从 query-frontend(如果您运行专用于规则评估的读取路径,则是 ruler-query-frontend)接收消息的最大大小。如果使用 jsonnet,只需调整 _config.ruler_remote_evaluation_max_query_response_size_bytes
    • 如果 ruler 日志记录了 gRPC 错误“trying to send message larger than max”,考虑在 query-frontend(如果您运行专用于规则评估的读取路径,则是 ruler-query-frontend)中增加 -server.grpc-max-send-msg-size-bytes。如果使用 jsonnet,只需调整 _config.ruler_remote_evaluation_max_query_response_size_bytes
  • 使用 Memberlist 作为哈希环的 KV 存储时,确保 Memberlist 正常工作。请参阅 MimirGossipMembersTooHighMimirGossipMembersTooLow 警报的说明。

MimirRulerMissedEvaluations

当某个规则组的评估时间超过其评估间隔时,会触发此警报。

工作原理

  • Mimir ruler 将根据规则组的评估间隔来评估规则组。
  • 如果一次评估在下一次评估应该发生时仍未完成,则会错过下一次评估。

如何解决

  • 增加规则组的评估间隔。您可以使用错过评估的速率来估计规则组评估实际需要的时间。
  • 尝试将规则组拆分为多个规则组。规则组是并行评估的,因此相同的规则可能仍然适用于相同的分辨率。

MimirRulerRemoteEvaluationFailing

rulerruler-query-frontend 之间的通信无法建立时,会触发此警报。

在远程操作模式下运行时,ruler-query-frontend 组件专供 ruler 用于评估规则表达式。如果这两个组件之间的通信中断,则对于记录规则可能会出现空隙,或者警报规则不会在应该触发时触发。

如何调查

  • 检查 Mimir / Remote ruler reads 仪表盘,查看问题是否由失败或高延迟引起
    • 失败
      • 检查 ruler-query-frontend 日志以了解错误的更多详细信息
    • 高延迟
      • 检查 Mimir / Remote ruler reads resources 仪表盘,查看 CPU 或内存使用率是否意外增加

MimirIngesterHasNotShippedBlocks

当 Mimir ingester 未将任何块上传到长期存储时,会触发此警报。ingester 预计每隔一个块范围周期(默认为 2 小时)将一个块上传到存储,如果自上次成功上传以来过去了更长时间,则表示某些功能未正常工作。

如何调查

  • 确保 ingester 正在接收写入路径流量(要摄取的样本)
  • 在 ingester 日志中查找任何上传错误(即网络或认证问题)

如果同时触发了警报 MimirIngesterTSDBHeadCompactionFailed,则优先处理它,因为这可能是原因。

Ingester 达到磁盘容量限制

如果 ingester 达到磁盘容量限制,任何追加样本的尝试都将失败。您应该

  1. 增加磁盘大小并重启 ingester。如果 ingester 在 Kubernetes 中使用持久卷运行,请参阅使用 Kubernetes 调整持久卷大小
  2. 调查为什么达到了磁盘容量限制
  • 磁盘是否太小了?
  • 压缩 TSDB head 是否有问题,导致 WAL 无限增长?

MimirIngesterHasNotShippedBlocksSinceStart

MimirIngesterHasNotShippedBlocks 相同。

MimirIngesterHasUnshippedBlocks

当 Mimir ingester 压缩了一些块但这些块尚未成功上传到存储时,会触发此警报。

如何调查

  • 在 ingester 日志中查找详细信息

MimirIngesterTSDBHeadCompactionFailed

当 Mimir ingester 无法将 TSDB head 压缩成块时,会触发此警报。

向 ingester 写入至少 1 个时间序列的每个租户都会打开一个 TSDB 实例,其 head 包含尚未刷新到块的内存中时间序列。一旦 TSDB head 可压缩,ingester 将每 1 分钟尝试压缩一次。如果 TSDB head 压缩反复失败,则表示至少有一个租户的内存中时间序列无法压缩成块,这是一个需要立即调查的关键状况。

触发此警报的原因可能导致

  • Ingester 内存不足
  • Ingester 磁盘空间不足
  • 查询在事件发生后 -querier.query-ingesters-within 时间返回部分结果

如何调查

  • 在 ingester 日志中查找详细信息

MimirIngesterTSDBHeadTruncationFailed

当 Mimir ingester 未能截断 TSDB head 时触发此警报。

TSDB head 是内存中的存储,用于保存尚未压缩成块的序列和样本。如果 head 截断长时间失败,由于无法进入 WAL 截断阶段,ingester 的磁盘可能会满,并且随后的 ingester 重启可能会花费很长时间,甚至由于巨大的 WAL 需要重放而进入 OOMKilled 崩溃循环。因此,一旦发生问题,立即调查和解决问题非常重要。

如何调查

  • 在 ingester 日志中查找详细信息

MimirIngesterTSDBCheckpointCreationFailed

当 Mimir ingester 未能创建 TSDB 检查点时触发此警报。

如何调查

  • 在 ingester 日志中查找详细信息
  • 如果由于 corruption in segment 导致检查点失败,您可以重启 ingester,因为在下次启动时 TSDB 将尝试“修复”它。重启后,如果问题已修复且 ingester 正在运行,您还应该收到 MimirIngesterTSDBWALCorrupted 警报,以通知您 WAL 已损坏,需要手动调查。

MimirIngesterTSDBCheckpointDeletionFailed

当 Mimir ingester 未能删除 TSDB 检查点时触发此警报。

一般来说,这不是一个紧急问题,但需要手动调查以找到问题的根本原因并进行修复。

如何调查

  • 在 ingester 日志中查找详细信息

MimirIngesterTSDBWALTruncationFailed

当 Mimir ingester 未能截断 TSDB WAL 时触发此警报。

如何调查

  • 在 ingester 日志中查找详细信息

MimirIngesterTSDBWALCorrupted

当多个 Mimir ingester 在启动时重放 WAL(存储在磁盘上)时发现损坏的 TSDB WAL,或者在创建检查点时遇到 WAL 损坏时,触发此警报。

如果此警报在 ingester 启动期间触发,WAL 应该已经自动修复,但需要手动调查。WAL 修复机制会导致数据丢失,因为损坏段之后的所有 WAL 记录都会被丢弃,因此在重放 WAL 时这些样本会丢失。如果这种情况仅发生在 1 个 ingester 或多区域集群中的一个区域上,则由于复制因子,Mimir 不会遭受任何数据丢失。但如果它发生在多个 ingester、多个区域或两者上,则可能会丢失一些数据。

要调查 ingester 如何处理 WAL 损坏,建议您搜索日志,例如使用以下 Grafana Loki 查询

{cluster="<cluster>",namespace="<namespace>", pod="<pod>"} |= "corrupt"

上述查询通常会产生以 ingester 发现 WAL 损坏(“Encountered WAL read error, attempting repair”)开头的条目,并且应该有望显示 ingester 修复了 WAL。

WAL 损坏可能发生在底层节点故障导致节点被标记为 NotReady(例如,意外断电、存储和/或网络故障)后 Pod 重新调度。检查与相关 ingester Pod 相关联的近期事件

kubectl get events --field-selector involvedObject.name=ingester-X

如果在 检查点创建期间触发此警报,您应该也收到了 MimirIngesterTSDBCheckpointCreationFailed 的警报,您可以按照该警报下的步骤进行操作。

MimirIngesterTSDBWALWritesFailed

当 Mimir ingester 未能将记录写入磁盘上的 TSDB WAL 时触发此警报。

如何调查

  • 在 ingester 日志中查找详细信息

MimirIngesterInstanceHasNoTenants

当 ingester 实例不拥有任何租户并因此处于空闲状态时触发此警报。

工作原理

  • Ingesters 加入哈希环,以便在 ingester 副本之间进行按租户的请求分片。
  • Distributors 将属于单个租户的请求分片到 ingester 副本的子集。每个租户使用的副本数量由 -distributor.ingestion-tenant-shard-sizeingestion_tenant_shard_size 限制决定。
  • 当租户分片大小低于 ingester 副本数量时,一些 ingester 可能不会收到任何租户的请求。
  • 这在租户数量较少的 Mimir 集群中更容易发生。

如何解决

选择以下三个选项之一

  • 增加一个或多个租户的分片大小以匹配 ingester 副本数量。
  • 将一个或多个租户的分片大小设置为 0;这将把给定租户的请求分片到所有 ingester 上。
  • 减少 ingester 副本数量 以匹配每个租户的最大分片数量。

MimirRulerInstanceHasNoRuleGroups

当 ruler 实例不拥有任何规则组并因此处于空闲状态时触发此警报。

工作原理

  • ruler shuffle sharding 启用时,单个租户的规则组会在 ruler 实例的子集之间分片,一个给定的规则组始终在一个 ruler 上评估。
  • 参数 -ruler.tenant-shard-sizeruler_tenant_shard_size 控制一个租户的规则组在多少个 ruler 实例之间分片。
  • 当规则组总数或租户分片大小低于 ruler 副本数量时,一些副本可能不会被分配任何规则组进行评估,并保持空闲。

如何解决

  • 增加一个或多个租户的分片大小以匹配 ruler 副本数量。
  • 将一个或多个租户的分片大小设置为 0;这将把给定租户的规则组分片到所有 ruler 实例上。
  • 减少 ruler 副本总数,减少量为空闲副本数量。

MimirStoreGatewayHasNotSyncTheBucket

当 Mimir store-gateway 未能成功扫描存储(存储桶)中的块时触发此警报。store-gateway 预计会定期迭代存储桶以查找新的和已删除的块(默认为每 5 分钟一次),如果长时间未能成功同步存储桶,可能最终只能查询一部分块,从而导致潜在的部分结果。

如何调查

  • 在 store-gateway 日志中查找任何扫描错误(即,网络或速率限制问题)

MimirStoreGatewayNoSyncedTenants

当 store-gateway 不拥有任何租户时触发此警报。实际上,它处于空闲状态,因为没有块分片给它。

工作原理

  • Store-gateways 加入哈希环,以便在所有 store-gateway 副本之间分片租户和块。
  • 一个租户可以被分片到多个 store-gateway。具体数量由 -store-gateway.tenant-shard-sizestore_gateway_tenant_shard_size 限制决定。
  • 当租户分片大小小于 store-gateway 副本数量时,一些 store-gateway 可能不会被分片到任何租户的块。
  • 这在租户数量较少的 Mimir 集群中更容易发生。

如何解决

有三个选项

  • 减少 store-gateway 副本数量,使其与每个租户的最大分片数量相匹配,或者
  • 增加一个或多个租户的分片大小以匹配副本数量,或者
  • 将一个或多个租户的分片大小设置为 0;这将把此租户的块分片到所有 store-gateway 上。

MimirCompactorHasNotSuccessfullyCleanedUpBlocks

当 Mimir compactor 长时间未能成功删除标记为删除的块时触发此警报。

如何调查

  • 确保 compactor 在压缩期间没有崩溃(例如,OOMKilled
  • 在 compactor 日志中查找任何错误(即,存储桶 Delete API 错误)

MimirCompactorHasNotSuccessfullyCleanedUpBlocksSinceStart

MimirCompactorHasNotSuccessfullyCleanedUpBlocks 相同。

MimirCompactorHasNotUploadedBlocks

当 Mimir compactor 长时间未向存储上传任何压缩后的块时触发此警报。

如何调查

  • 如果警报 MimirCompactorHasNotSuccessfullyRunCompaction 也已触发,则首先调查该问题
  • 如果警报 MimirIngesterHasNotShippedBlocksMimirIngesterHasNotShippedBlocksSinceStart 也已触发,则首先调查该问题
  • 确保 ingester 成功地将块发送到存储
  • 在 compactor 日志中查找任何错误

MimirCompactorHasNotSuccessfullyRunCompaction

如果 compactor 无法成功压缩所有发现的可压缩块(跨所有租户),则触发此警报。

当此警报触发时,compactor 可能仍然成功压缩了一些块,但由于某种原因,其他块的压缩持续失败。一个常见的情况是 compactor 试图压缩单个租户的损坏块:在这种情况下,其他租户的块压缩仍然正常工作,但受影响租户的压缩被损坏块阻塞。

如何调查

  • 在 compactor 日志中查找任何错误

    • 损坏:not healthy index found
    • 无效结果块
      • 如何检测:在 compactor 日志中搜索 invalid result block
      • 含义:Compactor 成功验证了源块。但压缩后的结果块验证失败。结果块未上传,压缩作业将重试。
    • 乱序块 (chunks)
      • 如何检测:在 compactor 日志中搜索 invalid result blockout-of-order chunks
      • 这是由 ingester 中的一个 bug 引起的 - 参见 mimir#1537。Ingesters 上传的块中,某些块的 MinT 和 MaxT 与块中的第一个和最后一个样本不匹配。当有问题的块的 MinT 和 MaxT 与其他块重叠时,compactor 会合并这些块。由于其中一个块的 MinT 和 MaxT 不正确,合并可能会被错误地执行,从而导致 OoO(乱序)样本。
      • 如何缓解:标记有问题的块,以便将来避免压缩它们
        • 在 compactor 日志中找到所有受影响的压缩组。您会找到类似 invalid result block /data/compact/<compaction_group>/<result_block> 的条目。
        • 对于每个失败的压缩作业
          • 选择一个结果块(哪个都无所谓)
          • 查找压缩作业的源块:搜索 msg="compact blocks" 并提及结果块 ID。
          • 标记源块为不压缩(在此示例中,对象存储后端是 GCS)
            ./tools/mark-blocks/mark-blocks -backend gcs -gcs.bucket-name <bucket> -mark-type no-compact -tenant <tenant-id> -details "Leading to out-of-order chunks when compacting with other blocks" -blocks "<block-1>,<block-2>..."
    • 结果块超出符号表最大大小
      • 如何检测:在 compactor 日志中搜索 symbol table size exceeds
      • 含义:Compactor 成功验证了源块。但由于上述错误,结果块无法写入。
      • 这是由于块中存储的序列过多造成的,这表明租户的 -compactor.split-and-merge-shards 设置过低。也可能是标签流失率非常高导致标签基数爆炸的迹象。
      • 如何缓解:这些块无法压缩,将错误消息中指示的源块标记为 no-compact
        • 通过搜索 symbol table size exceeds 在 compactor 日志中找到所有受影响的源块。
        • 日志行包含块 ID,格式为路径列表,例如
          [/data/compact/0@17241709254077376921-merge-3_of_4-1683244800000-1683331200000/01GZS91PMTAWAWAKRYQVNV1FPP /data/compact/0@17241709254077376921-merge-3_of_4-1683244800000-1683331200000/01GZSC5803FN1V1ZFY6Q8PWV1E]
          其中文件名是块 ID:01GZS91PMTAWAWAKRYQVNV1FPP01GZSC5803FN1V1ZFY6Q8PWV1E
        • 标记源块为不压缩(在此示例中,对象存储后端是 GCS)
          ./tools/mark-blocks/mark-blocks -backend gcs -gcs.bucket-name <bucket> -mark-type no-compact -tenant <tenant-id> -details "Result block exceeds symbol table maximum size" -blocks "<block-1>,<block-2>..."
      • 延伸阅读:压缩算法
    • Compactor 网络磁盘无响应
      • 如何检测:一个明显的迹象是 compactor 进程持续占用多个 CPU 核心的内核模式 CPU 使用率。检查受影响 Pod 的指标 rate(container_cpu_system_seconds_total{pod="<pod>"}[$__rate_interval])
      • 含义:Compactor 进程已冻结,因为它被阻塞在向无响应的网络块存储设备进行内核模式刷新上。
      • 如何缓解:未知。通常在十分钟到二十分钟后会自动恢复。
  • 检查 Compactor 控制面板 并将其设置为查看最近 7 天的数据。

    • Compactor 落后
      • 如何检测:
        • 检查 Last successful run per-compactor replica 面板 - 最近 6-12 小时内是否有成功运行的记录?
        • 同时检查 Average blocks / tenant 面板 - 趋势如何?租户的块数量不应持续增加。增长后进行压缩的模式是正常的。总块计数也可以检查,但这取决于集群中租户的使用时长和分片设置。从小于 1200 个块开始的值可能是正常的。通常 5 万个块就不正常了。
      • 含义:压缩过去可能因某种原因失败,现在以当前的配置和扩缩级别有太多工作需要追赶。这也可能导致长时间查询失败,因为 store-gateway 未能按预期处理数量多得多的较小块。
      • 如何缓解:重新配置并修改 compactor 设置和资源以提高可伸缩性
        • 确保您的 compactors 至少按照 容量规划 页面进行大小调整,并拥有推荐数量的副本。
        • -compactor.split-groups-compactor.split-and-merge-shards 设置为您拥有的每 8M 活动序列对应值为 1 的值 - 四舍五入到最接近的偶数。因此,如果您有 100M 序列 - 100/8 = 12.5 = 值为 12。如果您在 query frontend 上使用查询分片,建议改用下一个 2 的幂,以避免读路径上的额外工作(示例中值为 16 而不是 12),请参阅此博客文章了解更多信息
        • 让 compactor 运行几个小时,看看运行是否开始成功,以及 Average blocks / tenant 是否开始减少。
        • 如果您遇到任何 Compactor 资源问题,暂时增加 CPU/内存,稍后再缩减。
        • 您还可以选择进一步扩缩副本和分片,将工作分解成更小的部分,直到情况恢复。

MimirCompactorHasRunOutOfDiskSpace

当 compactor 至少一次磁盘空间不足时触发此警报。发生这种情况时,压缩将失败,一段时间后 compactor 将重试失败的压缩。很可能在每次重试作业时,compactor 会再次遇到相同的磁盘空间限制,并且无法自行恢复。或者,如果 compactor 并发性大于 1,可能只是作业的组合不走运导致 compactor 磁盘空间不足。

如何调查

  • 查看 compactor 数据卷中的磁盘空间使用情况。
  • 查找包含字符串 no space left on device 的错误,以确认 compactor 磁盘空间不足。

如何解决

  • 唯一的长期解决方案是为 compactor 提供更多磁盘空间,因为它需要更多空间来容纳最大的单个作业。
  • 如果 compactor 未能压缩的块数量不太多,并且您想跳过压缩它们而专注于更近期的块,请考虑标记受影响的块为不压缩
    ./tools/mark-blocks/mark-blocks -backend gcs -gcs.bucket-name <bucket> -mark-type no-compact -tenant <tenant-id> -details "focus on newer blocks" -blocks "<block 1>,<block 2>..."

MimirCompactorSkippedUnhealthyBlocks

当 compactor 尝试压缩块,但发现给定块不健康时触发此警报。这表明 Prometheus TSDB 库中存在 bug,应进行调查。

Compactor 因 not healthy index found 而失败

Compactor 可能因在其中一个源块中发现损坏的块索引而未能压缩块

level=error ts=2020-07-12T17:35:05.516823471Z caller=compactor.go:339 component=compactor msg="failed to compact user blocks" user=REDACTED-TENANT err="compaction: group 0@6672437747845546250: block with not healthy index found /data/compact/0@6672437747845546250/REDACTED-BLOCK; Compaction level 1; Labels: map[__org_id__:REDACTED]: 1/1183085 series have an average of 1.000 out-of-order chunks: 0.000 of these are exact duplicates (in terms of data and time range)"

发生这种情况时,受影响的块将被 compactor 标记为不可压缩,以防止下次执行被阻塞,这可能会对读路径的性能产生负面影响。

如果损坏仅影响级别 (level) 为 1 的一个块(信息存储在其 meta.json 中),则 Mimir 保证不会丢失数据,因为所有数据都在其他块中复制。在所有其他情况下,可能会丢失一些数据。

一旦触发此警报,建议遵循以下步骤

  1. 确保 compactor 已恢复。
  2. 通过下载损坏的块并在本地调试,离线调查根本原因

要下载存储在 GCS 上的块,您可以使用 gsutil CLI 命令

gsutil cp gs://[BUCKET_NAME]/[OBJECT_NAME] [LOCAL_DESTINATION]

其中

  • BUCKET 是 compactor 使用的 gcs 存储桶名称。集群的存储桶名称在集群配置中指定为 blocks_storage_bucket_name
  • TENANT 是上述示例错误消息中报告的租户 ID,例如 REDACTED-TENANT
  • BLOCK 是上述示例错误消息中报告的文件路径的最后一部分,例如 REDACTED-BLOCK

MimirCompactorFailingToBuildSparseIndexHeaders

-compactor.upload-sparse-index-headers 设置为 true 但 compactor 未能构建一些稀疏索引头部时触发此警报。

如何调查

  • 如果警报 MimirCompactorHasRunOutOfDiskSpace 也已触发,则首先调查该问题。如果磁盘空间不足,compactor 将无法在上传之前将稀疏头部写入本地磁盘。
  • 在 compactor 日志中查找任何错误,重点关注包含 method=indexheader.NewStreamBinaryReader 的日志。

MimirBucketIndexNotUpdated

当给定租户的存储桶索引长时间未更新时触发此警报。存储桶索引预计会由 compactor 定期更新,并被 queriers 和 store-gateways 用于获取存储桶存储的几乎最新的视图。

如何调查

  • 确保 compactor 成功运行
  • 在 compactor 日志中查找任何错误
  • 检查 compactor 清理任务失败了多久
    sum(rate(cortex_compactor_block_cleanup_failed_total{namespace="<namespace>"}[$__rate_interval]))
  • 检查 compactor 的对象存储故障
    sum(rate(thanos_objstore_bucket_operation_failures_total{namespace="<namespace>", component="compactor"}[$__rate_interval]))

如何解决

  • 暂时增加 queriers 对过期存储桶索引的容忍度
    -blocks-storage.bucket-store.bucket-index.max-stale-period=2h
  • 暂时增加 compactors 执行清理任务(如更新存储桶索引)的频率
    -compactor.cleanup-interval=5m

[!NOTE] 如果您同时看到此租户的查询未能通过一致性检查,这些缓解措施可能特别有用。

MimirInconsistentRuntimeConfig

如果同一 Mimir 服务的多个副本长时间使用不同的运行时配置,则触发此警报。

Mimir 运行时配置是 Mimir 在运行时实时重新加载的配置文件。为了使 Mimir 正常工作,同一 Mimir 服务(例如,distributors、ingesters 等)的多个副本加载的配置应完全相同。当配置更改时,可能存在一些短暂的时间段,在此期间某些副本已加载新配置,而其他副本仍在运行旧配置,但这不应持续超过几分钟。

如何调查

  • 检查报告了多少种不同的配置文件版本(哈希)
    count by (sha256) (cortex_runtime_config_hash{namespace="<namespace>"})
  • 检查哪些副本正在运行不同的版本
    cortex_runtime_config_hash{namespace="<namespace>",sha256="<unexpected>"}
  • 检查受影响副本的文件系统上运行时配置是否已更新。检查 -runtime-config.file 命令行参数以找到文件位置。
  • 检查受影响副本的日志,查找加载运行时配置的任何错误

MimirBadRuntimeConfig

如果 Mimir 无法重新加载运行时配置,则触发此警报。

这通常意味着部署了无效的运行时配置。Mimir 将继续使用先前的(有效)版本运行;正在运行的 Mimir 副本和系统可用性不应受到影响,但新的副本将无法启动,直到修复运行时配置。

如何调查

  • 检查最新的运行时配置更新(很可能已损坏)
  • 检查 Mimir 日志以获取有关配置问题的更多详细信息

MimirFrontendQueriesStuck

如果 Mimir 在没有 query-scheduler 的情况下运行,并且查询在 query-frontend 队列中堆积,则触发此警报。

调查它的过程与 MimirSchedulerQueriesStuck 的过程相同:请参阅其他运行手册了解更多详细信息。

MimirSchedulerQueriesStuck

如果查询在 query-scheduler 中堆积,则触发此警报。

控制面板面板

队列大小显示在 Mimir / Reads(用于标准查询路径)或 Mimir / Remote Ruler Reads(用于专用规则评估查询路径)控制面板上的 Queue Length 面板上。

Mimir / Reads(用于标准查询路径)和 Mimir / Remote Ruler Reads(用于专用规则评估查询路径)控制面板上的 Queue Length 面板显示队列大小。Latency (Time in Queue) 在下面的控制面板行中按“预期查询组件”进行细分 - 调度器队列本身按每个查询的预期查询组件进行分区,这是根据查询时间范围对 querier 使用哪个组件获取数据的估计

下面的行显示 Query-scheduler <-> Querier Inflight Requests 的峰值,也按查询组件细分。这显示了 queriers 被进行中的查询请求饱和的时间,以及用于服务查询的查询组件。

工作原理

  • 调用 query-frontend API 端点执行查询。
  • query-frontend 将请求入队到 query-scheduler。
  • query-scheduler 负责将入队的查询分派给空闲的 querier worker。
  • querier 从 ingesters、store-gateways 或两者获取数据,并对数据运行查询。然后,它直接将响应发送回 query-frontend,并通知 query-scheduler 它可以处理另一个查询。

如何调查

请注意,读路径任何部分中 进行中 查询数量的增加很可能是症状,而不是原因。

Ingester 或 Store-Gateway 问题

在 querier 自动扩缩到位的情况下,查询积压的最常见原因是 ingesters 或 store-gateways 无法跟上其查询负载。

调查 Mimir / Reads 控制面板上 ingesters 和 store-gateways 的 RPS 和延迟面板,并将此值与 Mimir / ReadsMimir / Remote Ruler Reads 控制面板上的 Latency (Time in Queue)Query-scheduler <-> Querier Inflight Requests 细分进行比较。此外,检查 Mimir / Reads Resources 控制面板是否有 ingesters 或 store-gateways 资源利用率升高或受限的情况。

一般来说,这表明 ingesters 或 store-gateways 其中一个正在经历问题,然后您可以进一步单独调查该查询组件。在这种情况下,扩缩 queriers 可能没有帮助,因为它会给已经过载的组件增加更多负载。

Querier 问题

  • queriers 是否处于崩溃循环中(例如,OOMKilled)?
    • OOMKilled:暂时增加 queriers 内存请求/限制
    • panic:在日志中查找堆栈跟踪并从那里调查
    • 如果 queriers 启用活动跟踪器运行,它们可能会在启动时记录 unfinished activities 消息,其中包含可能导致崩溃的查询。
  • QPS 是否增加?
    • 扩缩 queriers 以应对增加的工作负载
  • 查询延迟是否增加?
    • 延迟增加会减少我们每秒可以运行的查询数量:一旦所有 worker 都忙碌,新查询就会在队列中堆积
    • 暂时扩缩 queriers 以尝试止损
    • 检查是否有特定租户正在运行繁重查询
      • 运行 sum by (user) (cortex_query_scheduler_queue_length{namespace="<namespace>"}) > 0 查找有入队查询的租户
      • 如果启用了远程 ruler 评估,请确保您了解哪个读路径(用户查询还是 ruler 查询?)受到影响 - 检查警报消息。
      • 检查 [Mimir / Slow Queries] 控制面板以查找慢查询
    • 未禁用 queriers shuffle-sharing 的多租户 Mimir 集群中,您可以考虑为该特定租户启用它,以减小其影响范围。要为单个租户启用 queriers shuffle-sharding,您需要为该特定租户设置 max_queriers_per_tenant 限制覆盖(该值应设置为分配给该租户的 queriers 数量)。
    • 已启用 queriers shuffle-sharding 的多租户 Mimir 集群中,您可以考虑暂时增加受影响租户的分片大小:请注意,这可能会影响其他租户,减少可用于运行其他租户查询的资源。或者,您可以选择不采取任何措施,一旦每个租户的队列已满,Mimir 将为该给定用户返回错误。
    • 已启用 query-sharding多个租户受影响的多租户 Mimir 集群中:工作负载超过了可用的下游容量。应考虑扩缩 queriers 和可能还有 store-gateways。
    • 已启用 query-sharding仅一个租户受影响的多租户 Mimir 集群中
      • 通过从 Mimir / Slow Queries 控制面板获取跟踪来验证特定查询是否正在触及边缘情况(即 query-sharding 无益的情况),然后查看时间花在哪里。如果时间花在 query-frontend 运行 PromQL 引擎上,则意味着 query-sharding 对此租户无益。考虑禁用 query-sharding 或使用 query_sharding_total_shards 覆盖减少分片计数。
      • 否则,且仅当租户的查询在合理范围内代表正常使用时,才考虑扩缩 queriers 和可能还有 store-gateways。
    • 已启用 querier 自动扩缩的 Mimir 集群中,检查现有 querier 副本的健康状况后,查看自动扩缩器是否已添加额外的 querier 副本,或者是否已达到最大 querier 副本数量且不足,需要增加。

Query-Scheduler 问题

在极少数情况下,query-scheduler 本身可能成为瓶颈。当 Query-scheduler <-> Querier Inflight Requests 控制面板中的 querier 连接利用率较低,但队列长度或延迟较高时,表明 query-scheduler 在分派查询时非常缓慢。

在这种情况下,如果调度器没有资源限制,您可以使用 CPU 配置文件查看调度器的查询分派过程花费时间的地方。

MimirCacheRequestErrors

如果 Mimir 缓存客户端在特定缓存和操作中遇到高错误率,则触发此警报。

如何调查

  • 警报报告哪个缓存正在遇到问题
    • metadata-cache:对象存储元数据缓存
    • index-cache:TSDB 索引缓存
    • chunks-cache:TSDB 块 (chunks) 缓存
  • 检查正在发生哪种特定错误
    • 运行以下查询以找出原因(将 <namespace> 替换为实际的 Mimir 集群命名空间)
      sum by(name, operation, reason) (rate(thanos_cache_operation_failures_total{namespace="<namespace>"}[1m])) > 0
  • 根据 reason
    • timeout (超时)
      • 扩缩缓存副本
    • server-error (服务器错误)
      • 检查 Mimir 和缓存日志以查找更多详细信息
    • network-error (网络错误)
      • 检查 Mimir 日志以查找更多详细信息
    • malformed-key (格式错误的键)
      • 键过长或包含无效字符
      • 检查 Mimir 日志以查找有问题的键
      • 修复此问题需要修改应用程序代码
    • other (其他)
      • 检查 Mimir 和缓存日志以查找更多详细信息

MimirProvisioningTooManyWrites

如果 ingesters 每秒摄取的样本平均数量高于我们的目标,则触发此警报。

如何解决

  • 扩展 ingester
    • 要计算满足平均样本率所需的 ingesters 数量,您可以运行以下查询,将 <namespace> 替换为要分析的命名空间,将 <target> 替换为每个 ingester 每秒的目标样本数(查看警报阈值以了解当前目标)
      sum(rate(cortex_ingester_ingested_samples_total{namespace="<namespace>"}[$__rate_interval])) / (<target> * 0.9)

MimirAllocatingTooMuchMemory

当 ingester 内存利用率接近限制时触发此警报。

工作原理

  • Mimir ingesters 是有状态服务
  • 有两个或更多 ingester OOMKilled 可能导致集群中断
  • Ingester 内存基线使用主要受进程分配的内存(主要是 Go 堆)和 mmap 映射文件(由 TSDB 使用)的影响
  • Ingester 内存短期峰值主要受查询和 TSDB head 压缩成新块(每 2 小时发生一次)的影响
  • 一旦 pod 的工作集内存达到配置的限制,它就会被 OOMKilled,因此阻止 ingesters 的内存利用率(工作集内存)接近限制非常重要(我们需要至少留出 30% 的空间用于查询引起的峰值)

如何解决

  • 检查问题是否仅发生在少数 ingesters 上。如果是这样
    • 逐个重启受影响的 ingesters(在上一个 Pod 重启并准备就绪后继续下一个)
      kubectl --namespace <namespace> delete pod ingester-XXX
    • 重启 ingester 通常会减少 mmap 映射文件分配的内存。重启后,ingester 可能会随着时间推移再次分配此内存,但这可以在处理长期解决方案时争取更多时间。
  • 检查 Mimir / Writes Resources 控制面板,查看每个 ingester 的序列数量是否高于目标(150 万)。如果是这样
    • 扩缩 ingesters;例如,您可以使用 Mimir / Scaling 控制面板作为参考,以确定所需的 ingesters 数量(还要记住每个 ingester 应该处理约 150 万个序列,并且这些序列会在三个实例中复制)
    • 内存预计将在下一次 TSDB head 压缩时(每 2 小时发生一次)回收

MimirGossipMembersTooHigh

当任何实例将过多实例注册为 memberlist 集群的成员时触发此警报。

工作原理

  • 此警报适用于使用 memberlist 作为哈希环 KV 存储的情况。
  • 所有使用环的 Mimir 实例,无论类型如何,都加入单个 memberlist 集群。
  • 每个实例(即,memberlist 集群成员)应该看到所有 memberlist 集群成员,但不应看到任何其他实例(例如,来自 Loki 或 Tempo,或其他 Mimir 集群)。
  • 因此,以下内容对于每个实例都应相等
    • 报告的集群成员数量(memberlist_client_cluster_members_count
    • 当前使用 memberlist KV 存储用于哈希环的响应实例总数。
  • 在滚动更新期间,某些实例报告的成员数量可能高于预期,因为实例关闭的通知需要一些时间才能在集群中传播。

如何调查

  • 检查哪些实例报告的集群成员数量高于预期(memberlist_client_cluster_members_count 指标)
  • 如果大多数或所有实例报告的集群成员数量高于预期,则此集群可能已与其他集群合并
    • 使用该实例上的 /memberlist 管理页面检查每个实例视图中列出的实例,并确认列出的所有实例都在预期范围内
  • 如果只有少数实例报告的集群成员数量高于预期,这些实例可能正在经历 memberlist 通信问题
    • 使用以下指标检查实例是否正在发送和接收 memberlist 流量,以验证与其他成员的通信
      • memberlist_tcp_transport_packets_received_total
      • memberlist_tcp_transport_packets_sent_total
    • 如果存在流量,则使用以下指标验证发送或接收数据包时没有错误
      • memberlist_tcp_transport_packets_sent_errors_total
      • memberlist_tcp_transport_packets_received_errors_total
      • 通过搜索前缀为 TCPTransport: 的消息可以找到这些错误(以及其他错误)。
  • 直接来自 memberlist 的日志也会被 Mimir 记录;它们可能指示进一步调查的方向。可以通过标记 caller=memberlist_logger.go:<line> 来识别这些日志。

MimirGossipMembersTooLow

当任何实例将成员数量注册为过少时触发此警报。

工作原理

  • 此警报适用于使用 memberlist 作为哈希环 KV 存储的情况。
  • 所有使用环的 Mimir 实例,无论类型如何,都加入单个 memberlist 集群。
  • 每个实例(即,memberlist 集群成员)应该看到所有 memberlist 集群成员。
  • 因此,以下内容对于每个实例都应相等
    • 报告的集群成员数量(memberlist_client_cluster_members_count
    • 当前使用 memberlist KV 存储用于哈希环的响应实例总数。

如何调查

  • 检查哪些实例报告的集群成员数量低于预期(memberlist_client_cluster_members_count 指标)
  • 如果大多数或所有实例报告的集群成员数量低于预期,则可能存在配置问题阻止集群成员相互发现
    • 使用该实例上的 /memberlist 管理页面检查每个实例视图中列出的实例,并确认列出的所有预期实例
  • 如果只有少数实例报告的集群成员数量低于预期,这些实例可能正在经历 memberlist 通信问题
    • 使用以下指标检查实例是否正在发送和接收 memberlist 流量,以验证与其他成员的通信
      • memberlist_tcp_transport_packets_received_total
      • memberlist_tcp_transport_packets_sent_total
    • 如果存在流量,则使用以下指标验证发送或接收数据包时没有错误
      • memberlist_tcp_transport_packets_sent_errors_total
      • memberlist_tcp_transport_packets_received_errors_total
      • 通过搜索前缀为 TCPTransport: 的消息可以找到这些错误(以及其他错误)。
  • 直接来自 memberlist 的日志也会被 Mimir 记录;它们可能指示进一步调查的方向。可以通过标记 caller=memberlist_logger.go:<line> 来识别这些日志。

MimirGossipMembersEndpointsOutOfSync

gossip-ring 服务返回的端点列表不同步时触发此警报。

工作原理

  • Kubernetes 服务 gossip-ring 用于 Mimir 在启动时查找要加入的 memberlist 种子节点。默认情况下,服务 DNS 返回所有 Mimir pod,这意味着任何 Mimir pod 都可以用作种子节点(这是最安全的选项)。
  • 由于 Kubernetes bug(例如,此问题),服务 DNS 地址返回的 Pod IP 可能会不同步,甚至可能达到返回的 IP 都不属于任何活动 Pod 的程度。如果发生这种情况,新的 Mimir Pod 将无法在启动时加入 memberlist。

如何调查

  • 检查与 gossip-ring 服务匹配的端点数量

    kubectl --namespace <namespace> get endpoints gossip-ring -ojson | jq '.subsets[].addresses | length'
  • 如果端点数量为 1000,则意味着您已达到 Kubernetes 限制,端点被截断,您可能会受到 此 bug 的影响。由 gossip-ring 服务匹配的 Pod 数量超过 1000,然后端点被截断到 1000 本身不是问题,但如果您运行的 Kubernetes 版本受上述 bug 影响,那就是一个问题。

  • 如果您受到 Kubernetes bug 的影响

    1. 通过重新创建服务端点列表来止损

      sh
      CONTEXT="TODO"
      NAMESPACE="TODO"
      SERVICE="gossip-ring"
      
      # Re-apply the list of bad endpoints as is.
      kubectl --context "$CONTEXT" --namespace "$NAMESPACE" get endpoints "$SERVICE" -o yaml > /tmp/service-endpoints.yaml
      kubectl --context "$CONTEXT" --namespace "$NAMESPACE" apply -f /tmp/service-endpoints.yaml
      
      # Delete a random querier pod to trigger K8S service endpoints reconciliation.
      POD=$(kubectl --context "$CONTEXT" --namespace "$NAMESPACE" get pods -l name=querier --output="jsonpath={.items[0].metadata.name}")
      kubectl --context "$CONTEXT" --namespace "$NAMESPACE" delete pod "$POD"
    2. 考虑从 gossip-ring selector label 中移除一些 Deployment,以减少匹配的 Pod 数量到 1000 以下。这是一个临时解决方案,一旦您将 Kubernetes 升级到已修复该 bug 的版本,就应该恢复。

      使用 jsonnet 实现的示例

      querier_deployment+:
        $.apps.v1.statefulSet.spec.template.metadata.withLabelsMixin({ [$._config.gossip_member_label]: 'false' }),

EtcdAllocatingTooMuchMemory

如果 etcd 中存在过多 HA 重复数据删除 (dedupe) 键,可能会触发此警报。我们在一个集群遇到 2 万个租户使用 HA dedupe 配置时看到了这种情况。通过以下方式提高 etcd 限制

  etcd+: {
    spec+: {
      pod+: {
        resources+: {
          limits: {
            memory: '2Gi',
          },
        },
      },
    },
  },

请注意,您可能需要重新创建每个 etcd Pod 才能使此更改生效,因为 etcd-operator 不会自动重新创建 Pod 以响应此类更改。首先,检查所有 etcd Pod 是否正在运行且健康。然后逐个删除一个 Pod,并等待它重新创建并变为健康,然后再重复此过程,直到所有 Pod 都已重新创建。

MimirAlertmanagerSyncConfigsFailing

工作原理

当多租户 alertmanager 无法从远程对象存储加载 alertmanager 配置至少 30 分钟时,触发此警报。

加载 alertmanager 配置可能发生在以下情况

  1. 当多租户 alertmanager 启动时
  2. 每次它在 alertmanager 中轮询配置更改时
  3. 当环发生变化时

此警报的指标是 cortex_alertmanager_sync_configs_failed_total,并在上述任一情况失败时递增。

当环发生变化或间隔时间已过时,从存储加载配置失败会记录为警告。

如何调查

查看记录的错误消息,尝试理解失败原因。例如,可能是网络问题、存储配置不正确等。

MimirAlertmanagerRingCheckFailing

工作原理

当多租户 alertmanager 在至少 10 分钟内无法检查此分片是否应拥有一个或多个租户时,触发此警报。

当 alertmanager 在启动时加载其配置、轮询配置更改或环发生变化时,它必须检查环以查看此分片是否仍然拥有该租户。为了防止一个错误导致所有配置加载失败,我们假设在出错时此分片不拥有该租户。如果检查环持续失败,则某些租户可能没有分配到 alertmanager,并且可能无法接收其警报的通知。

此警报的指标是 cortex_alertmanager_ring_check_errors_total

如何调查

  • 查看记录的错误消息,尝试理解失败原因。在大多数情况下,错误会在尝试从环中读取时遇到,如果在使用的后端实现中存在问题,读取可能会失败。
  • 使用 Memberlist 作为哈希环的 KV 存储时,确保 Memberlist 正常工作。请参阅 MimirGossipMembersTooHighMimirGossipMembersTooLow 警报的说明。

MimirAlertmanagerPartialStateMergeFailing

工作原理

当多租户 alertmanager 尝试合并它不知道的某些内容的 partial state,或者 partial state 无法与现有本地 state 合并时,触发此警报。State 合并是 gRPC 消息,在分片和相应警报管理器实例之间通过 gossip 在其他分片中传播。

此警报的指标是 cortex_alertmanager_partial_state_merges_failed_total

如何调查

接收方目前未记录此错误。如果此警报正在触发,很可能 MimirAlertmanagerReplicationFailing 也正在触发,因此请遵循该警报的调查步骤,假设问题与 RPC/通信无关。

MimirAlertmanagerReplicationFailing

工作原理

当多租户 alertmanager 尝试将租户的状态更新(即,静默或通知)复制到另一个 alertmanager 实例但失败时,触发此警报。这可能是由于 RPC/通信错误,或另一个 alertmanager 无法将其状态与自己的本地状态合并所致。

此警报的指标是 cortex_alertmanager_state_replication_failed_total

如何调查

状态复制失败时,会在尝试进行状态复制的 alertmanager 中记录错误。检查日志中的错误消息以了解错误原因(例如,是由于 RPC/通信错误,还是接收 alertmanager 中发生了错误)。

MimirAlertmanagerPersistStateFailing

工作原理

当多租户 alertmanager 无法将其状态持久化到远程对象存储时,触发此警报。此操作会定期尝试(默认为每 15 分钟一次)。

每个 alertmanager 将其状态(静默、通知日志)写入远程对象存储,每次失败时 cortex_alertmanager_state_persist_failed_total 指标会递增。如果失败持续一小时或更长时间,则触发警报。

如何调查

每次持久化状态到远程对象存储失败都会被记录下来。在 Alertmanager 容器日志中查找文本“failed to persist state”以找到原因。可能的原因

  • 最可能的原因是远程写入失败。尝试根据消息调查失败原因(网络问题、存储问题)。如果错误表明问题可能是暂时的,您可以等待下次定期尝试,看看是否成功。
  • 也可能状态编码失败。这不取决于外部因素,因为它只是从 Alertmanager 内部状态中提取状态。它可能表明编码方法存在 bug。

MimirAlertmanagerInitialSyncFailed

工作原理

当租户副本被拥有时,它会分配给一个 alertmanager 实例。alertmanager 实例尝试从其他 alertmanager 实例读取状态。如果没有其他 alertmanager 实例可以复制完整状态,则它会尝试从远程对象存储读取完整状态。当这两项操作都失败时,触发此警报。

请注意,远程对象存储中没有该用户的状态的情况不视为失败。这在新的租户首次变为活动状态时是预期的。

如何调查

当 alertmanager 无法从存储读取租户状态时,会记录以下错误:“failed to read state from storage; continuing anyway”。此错误可能的原因是

  • 状态无法合并,因为它可能无效且无法解码。这可能表明数据损坏,因此读写状态存在 bug,需要进一步调查。
  • 无法从存储读取状态。这可能是由于网络问题(如超时),或与远程对象存储的身份验证和授权问题所致。

MimirAlertmanagerAllocatingTooMuchMemory

当 alertmanager 内存利用率接近限制时触发此警报。

工作原理

  • Mimir alertmanager 是一个有状态服务
  • 有两个或更多 alertmanager OOMKilled 可能导致服务中断,因为它需要仲裁来响应 API 请求。通知(从 alertmanager 到第三方)可以在没有仲裁的情况下成功。
  • Alertmanager 内存基线使用主要受进程分配的内存(主要是 Go 堆)用于警报和静默的影响。
  • 一旦 pod 的工作集内存达到配置的限制,它就会被 OOMKilled,因此阻止 alertmanager 的内存利用率(工作集内存)超过限制非常重要。内存使用通常是持续的,不会出现峰值,因此阈值设置得非常接近限制。

如何解决

  • 扩缩 alertmanager 副本;例如,您可以使用 Mimir / Scaling 控制面板作为参考,以确定所需的 alertmanager 数量。

MimirAlertmanagerInstanceHasNoTenants

当 alertmanager 实例不拥有任何租户并因此处于空闲状态时触发此警报。

工作原理

  • 由 alertmanagers 处理的警报按租户分片。
  • 当租户分片大小低于 alertmanager 副本数量时,一些副本将不拥有任何租户并因此空闲。
  • 这在租户数量较少的 Mimir 集群中更容易发生。

如何解决

  • 减少 alertmanager 副本数量

MimirRolloutStuck

当 Mimir 服务滚动更新卡住,这意味着更新的副本数量与预期数量不符且看起来没有进展时触发此警报。警报监控部署为 Kubernetes StatefulSetDeployment 的服务。

如何调查

  • 运行 kubectl --namespace <namespace> get pods --selector='name=<statefulset|deployment>' 获取正在运行的 Pod 列表
  • 确保没有 Pod 处于失败状态(例如,ErrorOOMKilledCrashLoopBackOff
  • 确保没有 Pod 处于 NotReady 状态(就绪容器数量应与容器总数匹配,例如,1/12/2
  • 运行 kubectl --namespace <namespace> describe statefulset <name>kubectl --namespace <namespace> describe deployment <name> 并查看“Pod Status”和“Events”以获取更多信息

MimirKVStoreFailure

如果 Mimir 实例未能对 KV 存储(例如,consul 或 etcd)执行任何操作,则触发此警报。当使用 Memberlist 作为哈希环的 KV 存储时,所有读取和更新操作都在哈希环的本地副本上工作,并且永远不会失败并触发此警报。

工作原理

  • Consul 通常用于存储哈希环状态。
  • Etcd 通常由 HA tracker (distributor) 用于存储数据以对样本进行重复数据删除。
  • 如果实例在 哈希环 上操作失败,则实例无法更新环中的心跳或无法接收环更新。
  • 如果实例在 HA tracker 后端操作失败,则实例无法更新权威副本或无法接收更新。

如何调查

  • 确保 Consul/Etcd 正在运行。
  • 调查受影响实例的日志,查找与 Consul/Etcd 通信时发生的特定错误。

MimirReachingTCPConnectionsLimit

如果 Mimir 实例配置了 -server.http-conn-limit-server.grpc-conn-limit 并达到限制,则触发此警报。

工作原理

  • Mimir 服务可以配置 HTTP 和/或 gRPC 端口同时接受的最大 TCP 连接数限制。
  • 如果达到限制
    • 新连接的接受将被暂停或拒绝。具体行为取决于 listen() 调用的 backlog 参数和内核设置。
    • 健康检查端点可能失败(例如,超时)。
  • 限制通常设置得远高于预期使用量,因此如果达到或接近限制,则意味着存在严重问题。

如何调查

  • gateway 中达到限制
    • 检查是否由 写路径上的高延迟 引起
      • 检查 Mimir / Writes 控制面板中 distributors 和 ingesters 的延迟
      • 写路径上的高延迟可能导致我们的客户 Prometheus / Agent 几乎同时增加分片数量,从而导致负载均衡器以及 gateway 的并发请求数量显著增加
    • 检查是否由 单个租户 引起
      • 我们没有按租户跟踪活跃 TCP 连接或 QPS 的指标
      • 作为一个代理指标,您可以检查任何租户的摄取速率是否显著增加(这不是一个非常准确的 TCP 连接数代理指标,所以仅供参考)
      topk(10, sum by(user) (rate(cortex_distributor_samples_in_total{namespace="<namespace>"}[$__rate_interval])))
      • 如果您需要快速拒绝单个租户的写路径流量,可以覆盖其 ingestion_rateingestion_rate_burst 设置较低的值(以便其部分/大部分流量将被拒绝)

MimirAutoscalerNotActive

当 Mimir 的任何 Kubernetes Horizontal Pod Autoscaler (HPA) 的 ScalingActive 条件为 false 且相关扩缩指标不为 0 时触发此警报。发生这种情况时,它无法计算所需的扩缩值,通常表明获取指标有问题。

工作原理

  • HPA 可以配置为基于通过 KEDA 自定义指标 API 服务器从 Prometheus 获取的自定义指标自动扩缩 Mimir 组件
  • HPA 定期查询更新的指标,并根据此更新所需的副本数量
  • 有关更多信息,请参阅 Mimir 自动扩缩文档 和上游 HPA 文档

如何调查

  • 检查 HPA 条件和事件以获取有关失败的更多详细信息
    kubectl describe hpa --namespace <namespace> keda-hpa-$component
  • 确保 KEDA Pod 正在运行
    # Assuming KEDA is running in a dedicated namespace "keda":
    kubectl get pods --namespace keda
  • 检查 KEDA 自定义指标 API 服务器日志
    # Assuming KEDA is running in a dedicated namespace "keda":
    kubectl logs --namespace keda deployment/keda-operator-metrics-apiserver
  • 检查 KEDA operator 日志
    # Assuming KEDA is running in a dedicated namespace "keda":
    kubectl logs --namespace keda deployment/keda-operator
  • 检查 Prometheus 是否正在运行(因为我们默认配置 KEDA 从中抓取自定义指标)
    # Assuming Prometheus is running in namespace "default":
    kubectl --namespace default get pod --selector='name=prometheus'
  • 如果 Prometheus 看似健康,请检查其分配的 CPU 是否足够

对于 minReplicas 为 0 的 ScaledObject,当 keda_scaler_metrics_value 中暴露的扩缩指标为 0 时,HPA 预期会处于非活动状态。当 keda_scaler_metrics_value 值为 0 或缺失时,不应触发警报。

MimirAutoscalerKedaFailing

当 KEDA 报告在部署 Mimir 的同一 Kubernetes 命名空间中定义的任何 ScaledObject 存在错误时触发此警报。

工作原理

如何调查

  • 检查 KEDA 自定义指标 API 服务器日志
    # Assuming KEDA is running in a dedicated namespace "keda":
    kubectl logs --namespace keda deployment/keda-operator-metrics-apiserver
  • 检查 KEDA operator 日志
    # Assuming KEDA is running in a dedicated namespace "keda":
    kubectl logs --namespace keda deployment/keda-operator
  • 检查 Prometheus 是否正在运行(因为我们默认配置 KEDA 从中抓取自定义指标)
    # Assuming Prometheus is running in namespace "default":
    kubectl --namespace default get pod --selector='name=prometheus'
  • 如果 Prometheus 看似健康,请检查其分配的 CPU 是否足够

MimirContinuousTestNotRunningOnWrites

mimir-continuous-test 部署在 Mimir 集群中,且由于写入失败导致连续测试未能有效运行时触发此警报。

工作原理

  • mimir-continuous-test 是一个可选的测试工具,可以部署在 Mimir 集群中
  • 该工具定期针对 Mimir 集群本身运行一些测试
  • 此警报在该工具无法正常运行测试时触发,而不是在工具断言与预期结果不符时触发

如何调查

  • 检查连续测试日志以查找有关失败的更多详细信息
    kubectl logs --namespace <namespace> deployment/continuous-test

MimirContinuousTestNotRunningOnReads

此警报类似于 MimirContinuousTestNotRunningOnWrites,但在查询失败时触发。

MimirContinuousTestFailed

mimir-continuous-test 部署在 Mimir 集群中,且连续测试工具的断言与预期结果不符时触发此警报。当此警报触发时,Mimir 可能存在 bug,应尽快调查。

工作原理

  • mimir-continuous-test 是一个可选的测试工具,可以部署在 Mimir 集群中
  • 该工具定期针对 Mimir 集群本身运行一些测试
  • 如果工具断言与预期结果不符,则触发此警报

如何调查

  • 检查连续测试日志以查找有关失败断言的更多详细信息
    kubectl logs --namespace <namespace> deployment/continuous-test
  • 检查查询结果比较是否失败
    • 无论结果缓存启用还是禁用,查询是否都失败?
  • 此警报应始终可采取行动。有两种可能的结果
    1. 警报因 Mimir 中的 bug 触发:修复它。
    2. 警报因连续测试工具中的 bug 或边缘情况触发,导致误报:修复它。

MimirRingMembersMismatch

当环成员数量与正在运行的副本数量不匹配时触发此警报。

工作原理

  • 警报将每个组件(当前仅 ingester)与该集群中组件的 up 实例数量进行比较。

如何调查

  • 检查警报触发组件的 哈希环网页,查找列表中的意外实例。
  • 考虑手动忘记处于 Unhealthy 状态的意外实例。
  • 确保环中所有注册的实例都属于触发警报的 Mimir 集群。

RolloutOperatorNotReconciling

如果 rollout-operator 未能在一个命名空间中成功协调,则触发此警报。

工作原理

  • rollout-operator 协调同一命名空间内不同 StatefulSets 之间的 Pod 滚动更新,并用于管理多区域部署
  • rollout-operator 部署在一些 Mimir 组件(例如 ingesters)以多区域模式部署的命名空间中
  • rollout-operator 在观测到的 Kubernetes 资源发生任何变化时立即协调,或者最多每 5 分钟协调一次

如何调查

  • 检查 rollout-operator 日志以查找更多错误详细信息,例如使用以下 Grafana Loki 查询
    {name="rollout-operator",namespace="<namespace>"}

MimirIngestedDataTooFarInTheFuture

当 Mimir ingester 接受了时间戳在未来过远的样本时触发此警报。这通常是处理损坏消息的结果,可能导致拒绝时间戳接近“现在”(现实世界时间)的其他样本。

工作原理

  • ingester 导出的指标计算 ingester 中所有打开的 TSDB 的最大时间戳。
  • 警报检查此导出指标,如果最大时间戳超出未来 1 小时,则触发。

如何调查

  • 在 ingester 的租户列表中找到带有不良样本的租户,其中会显示警告“TSDB Head max timestamp too far in the future”。
  • 将租户的数据刷新到块存储。
  • 删除磁盘上租户的目录并重启 ingester。

MimirStoreGatewayTooManyFailedOperations

工作原理

  • store-gateways 在与对象存储交互时长时间报告错误时触发此警报。
  • 这通常是因为 Mimir 由于对象本身或对象存储的问题而无法读取对象。

如何调查

  • 检查 store-gateways 日志,其中应包含有关错误的详细信息,例如租户或对象 ID,例如使用以下 Grafana Loki 查询
{cluster="<cluster>",namespace="<namespace>", name=~"store-gateway.*"} |= "level=warn"

您可能会发现类似以下的日志

create index header reader: write index header: new index reader: get TOC from object storage of 01H9QMTQRE2MT8XVDWP6RWAMC6/index: Multipart upload has broken segment data.
  • 使用 Mimir / Object Store 控制面板检查错误率和受影响的失败对象存储操作,例如:get_range

KubePersistentVolumeFillingUp

此警报未在 Mimir mixin 中定义,但它是 kube-prometheus 警报的一部分。当 PersistentVolume 接近容量时触发此警报。

Compactor

工作原理

  • compactor 使用该卷临时存储待压缩的块。compactor 不需要持久性,因此停止 compactor,删除卷内容并以空磁盘重新启动是安全的。
  • compactor 磁盘利用率通常是作为压缩作业一部分待压缩的源块大小和配置的最大并发压缩数 (-compactor.compaction-concurrency) 的函数。

如何解决

  • 增加 compactor 卷大小以止损。您可以选择
    • 调整卷大小
    • 删除 compactor StatefulSet 及其 PersistentVolumeClaims,然后以更大的卷大小请求重新创建 compactor StatefulSet
  • 检查 compactor 是否配置了 -compactor.compaction-concurrency 大于 1,并且受影响的 compactor 中有多个并发压缩正在运行。如果是这样,可以考虑降低并发性。

Store-gateway

工作原理

  • 长期存储中的块使用 store-gateway 哈希环在 store-gateway 副本之间分片和复制。这意味着每个 store-gateway 拥有块的一个子集。
    • 分片算法旨在尝试均匀平衡每个 store-gateway 副本的块数量,但不平衡其大小。这意味着在租户块大小不均匀的情况下,即使分配给每个副本的块数量完全平衡,某些 store-gateway 也可能比其他 store-gateway 使用更多磁盘空间。
    • 分片算法只能在块数量很大时才能在 store-gateway 副本之间实现块数量的公平平衡。这意味着在块数量较少的 Mimir 集群中,这些块可能不会在副本之间均匀平衡。目前,在 store-gateway 副本之间实现完美(甚至非常好的)平衡几乎不可能。
    • 当租户使用 store-gateway shuffle sharding 且租户的分片大小小于 store-gateway 副本数量时,租户的块仅在副本子集之间分片。Shuffle sharding 可能导致 store-gateway 磁盘利用率不平衡。
  • store-gateway 使用卷存储每个拥有块的 索引头部 (index-header)

如何调查修复

  • 检查 Mimir / Compactor 控制面板

    • 确保 compactor 健康并成功运行。
      • “Last successful run per-compactor replica” 面板应显示所有 compactors 运行正常,没有处于 Delayed、Late 或 Very Late 状态。
      • “Tenants with largest number of blocks” 不得呈上升趋势
    • compactor 中的问题(例如 compactor 崩溃、OOMKilled 或无法赶上压缩作业)会导致未压缩块数量增加,从而导致 store-gateway 磁盘利用率增加。如果 compactor 出现问题,应首先修复它
      • 如果 compactor 发生 OOMKilled,增加 compactor 内存请求。
      • 如果 compactor 落后或有许多块需要压缩,暂时增加 compactor 副本数量以让 compactor 快速赶上。
  • 检查 Mimir / Reads resources 控制面板

    • 检查磁盘利用率在 store-gateway 副本之间是否几乎平衡(例如,副本之间预期有 20-30% 的差异)
      • 如果磁盘利用率几乎平衡,您可以横向扩缩 store-gateway 副本以降低平均磁盘利用率
      • 如果磁盘利用率不平衡,在横向扩缩 store-gateways 之前,您可以考虑其他选项
  • 检查磁盘利用率不平衡是否由 shuffle sharding 引起

    • 调查哪些租户在磁盘利用率最高的副本中使用了最多的 store-gateway 磁盘空间。为此,您可以为给定的 store-gateway 副本运行以下命令。该命令返回按磁盘利用率(以兆字节为单位)排名前 10 的租户

      kubectl --context $CLUSTER --namespace $NAMESPACE debug pod/$POD --image=alpine:latest --target=store-gateway --container=debug -ti -- sh -c 'du -sm /proc/1/root/data/tsdb/* | sort -n -r | head -10'
    • 检查每个主要导致磁盘利用率高的租户配置的 -store-gateway.tenant-shard-size (store_gateway_tenant_shard_size)。如果租户的分片大小小于可用 store-gateway 副本的数量,请考虑增加其分片大小(值为 0 会禁用租户的 shuffle sharding,有效地将其块分片到所有副本中)。

  • 检查磁盘利用率不均衡是否由块大小不均衡的租户引起

    • 即使租户没有 shuffle sharding,其块已分片到所有副本中,如果其块的大小随时间显著变化(例如,因为每个块的系列数量随时间显著变化),仍然可能导致 store-gateway 磁盘利用率不均衡。作为代理指标,每个块的系列数量大约是最大 -compactor.block-ranges(默认为 24 小时)的所有块中的总系列数量除以 -compactor.split-and-merge-shards (compactor_split_and_merge_shards) 的数量。
    • 如果您怀疑这可能是问题所在
      • 通过 store-gateway 在 /store-gateway/tenant/<tenant ID>/blocks 页面上检查受影响租户的 store-gateway 块列表中每个块的系列数量
      • 查看 Mimir / Tenants 控制面板上显示的内存中系列数量,以大致了解这些块从 ingester 传输后将被压缩的系列数量。
      • 检查租户配置的 compactor_split_and_merge_shards。一个合理的经验法则是每个 compactor 分片 8-10 百万系列——如果每个分片的系列数量超出此范围,请相应地增加受影响租户的 compactor_split_and-merge-shards
  • 检查持久卷是否接近其限制,并确定是否需要增加。

    • 如果 store-gateway 需要调整持久卷大小且启用了自动缩减,则在进行调整过程之前必须禁用它。此步骤是必要的,以防止 rollout operator 在更新每个区域的 stateful set 时发生意外缩减。要禁用 store-gateway 的自动缩减,请设置 $._config.store_gateway_automated_downscale_enabled = false
    jsonnet
    {
      _config+:
      {
        store_gateway_automated_downscale_enabled: false
      }
    }
    • 调整过程完成后,撤消此更改。

Mimir ingest storage(实验性)

本节包含与实验性 Mimir ingest storage 相关的警报的 runbook。在此上下文中,任何提及 Kafka 的地方都指兼容 Kafka 协议的后端。

MimirIngesterLastConsumedOffsetCommitFailed

当 ingester 未能将最后消耗的 offset 提交到 Kafka 后端时,此警报会触发。

工作原理

  • ingester 从 Kafka 接收数据(指标、exemplar 等),并定期将最后消耗的 offset 提交回 Kafka。
  • 启动时,ingester 读取提交到 Kafka 的最后消耗的 offset,并从那里恢复消费。
  • 如果 ingester 未能将最后消耗的 offset 提交到 Kafka,从消费的角度来看,ingester 仍然可以正常工作(假设集群中没有其他正在发生的问题),但在重启的情况下,ingester 将从最后成功提交的 offset 恢复消费。如果上次 offset 成功提交是在几分钟前,则 ingester 将重新接收已经接收过的数据,这可能导致 OOO 错误,浪费资源并增加启动时间。

如何调查

  • 检查 ingester 日志以查找错误的详细信息。
  • 检查 Kafka 日志和健康状况。

MimirIngesterFailedToReadRecordsFromKafka

当 ingester 未能从 Kafka 后端读取 records 时,此警报会触发。

工作原理

  • Ingester 连接到 Kafka brokers 并从中读取 records。Records 包含 distributors 提交的写入请求。
  • 当 ingester 由于错误无法从 Kafka 读取更多 records 时,ingester 会记录此类错误。
  • 如果 Kafka brokers 正在重启,这可能是正常的,但如果读取错误持续一段时间,则会触发警报。

如何调查

  • 检查 ingester 日志以查找错误的详细信息。
  • 检查 Kafka 日志和健康状况。

MimirIngesterKafkaFetchErrorsRateTooHigh

当 ingester 从 Kafka 接收到 errors 而不是 “fetches” 时,此警报会触发。

工作原理

  • Ingester 使用 Kafka 客户端从 Kafka 读取 records(包含写入请求)。
  • Kafka 客户端可能返回 errors 而不是更多 records。
  • 如果返回的 errors 与返回的 records 相比的比率过高,则会触发警报。
  • Kafka 客户端可能返回 源代码中记录的错误

如何调查

  • 检查 ingester 日志以查找错误的详细信息。
  • 检查 Kafka 日志和健康状况。

MimirStartingIngesterKafkaReceiveDelayIncreasing

当 ingester 在“starting”阶段报告的“receive delay”没有减少时,此警报会触发。

工作原理

  • 当 ingester 启动时,它需要从 Kafka fetches 和处理 records,直到达到预配置的 consumption lag。有两个配置选项控制 ingester 在启动时被认为已从分区中追赶上读取之前所需的 lag:
    • -ingest-storage.kafka.max-consumer-lag-at-startup:这是 ingester 被认为已追赶上之前的最大 lag。ingester 不会在 hash ring 中变为 ACTIVE 状态,也不会通过 readiness check,直到测量的 lag 低于此设置。
    • -ingest-storage.kafka.target-consumer-lag-at-startup:这是 ingester 在启动时力求达到的期望最大 lag。此设置为 best-effort。ingester 会获得一个“grace period”来使其测量的 lag 低于此设置。但是,如果在此“grace period”内未达到 target lag,只要 max lag 得到遵守,ingester 仍然会启动。“grace period”等于配置的 -ingest-storage.kafka.max-consumer-lag-at-startup
  • 每个 record 都有一个 timestamp,记录了它何时由 distributor 发送到 Kafka。当 ingester 读取 record 时,它会计算“receive delay”,即当前时间(读取 record 的时间)与将 record 发送到 Kafka 的时间之间的差值。此 receive delay 在指标 cortex_ingest_storage_reader_receive_delay_seconds 中报告。您可以在 Mimir / Writes 控制面板的“Ingester (ingest storage – end-to-end latency)”部分查看 receive delay。
  • 在正常情况下,当 ingester 处理 records 的速度快于 records 出现的数量时,receive delay 应该减少,直到 -ingest-storage.kafka.max-consumer-lag-at-startup 得到遵守。
  • 当 ingester 正在启动,并且观察到的“receive delay”正在增加时,会触发警报。

如何调查

  • 检查 ingester 是否足够快以处理 Kafka 中的所有数据。

另请参阅“ Ingester 在从 Kafka 消费时过载”。

MimirRunningIngesterReceiveDelayTooHigh

当 ingester 在运行时报告的“receive delay”达到警报阈值时,此警报会触发。

工作原理

  • ingester 启动并追赶上 Kafka 中的 records 后,它会切换到“running”模式。
  • 在 running 模式下,ingester 继续处理来自 Kafka 的传入 records,并继续报告“receive delay”。有关此指标的详细信息,请参阅MimirStartingIngesterKafkaReceiveDelayIncreasing runbook。
  • 在正常情况下,当 ingester 正在运行并且处理 records 的速度快于 records 出现的数量时,receive delay 应该稳定且较低。
  • 如果观察到的“receive delay”增加并达到特定阈值,则会触发警报。

如何调查

  • 检查 ingester 是否足够快以处理 Kafka 中的所有数据。
  • 如果 ingester 太慢,请考虑水平扩展 ingester 以在更多 ingester 之间分散传入的系列。

另请参阅“ Ingester 在从 Kafka 消费时过载”。

MimirIngesterFailsToProcessRecordsFromKafka

当 ingester 由于内部错误无法处理来自 Kafka 的传入 records 时,此警报会触发。如果未使用 ingest-storage,此类 push 请求将以 5xx 错误结束。

工作原理

  • ingester 从 Kafka 读取 records,并在本地处理它们。处理意味着解组数据和处理存储在 records 中的写入请求。
  • 写入请求可能由于“client”或“server”错误而失败。client 错误的示例是系列数量限制过低。server 错误例如 ingester 达到实例限制。
  • 如果请求因 server 错误而持续失败,则会触发此警报。

如何调查

  • 检查 ingester 日志以查看请求失败的原因,并据此排除故障。

MimirIngesterStuckProcessingRecordsFromKafka

当 ingester 已成功从 Kafka fetches records 但根本没有处理它们时,此警报会触发。

工作原理

  • ingester 从 Kafka 读取 records,并在本地处理它们。处理意味着解组数据和处理存储在 records 中的写入请求。
  • 获取的包含写入请求的 records,应通过将写入请求数据接收到 ingester 中进行处理。
  • 如果根本没有发生处理,例如处理 stuck(例如,ingester 中存在死锁),则会触发此警报。

如何调查

  • 获取 ingester 的 goroutine profile,并检查是否有任何 routine 调用 pushToStorage
    • 如果调用存在并且正在等待锁,则可能存在死锁。
    • 如果调用不存在,则可能意味着处理没有 stuck(false positive),或者根本没有调用 pushToStorage,因此您应该在代码中调查调用者。

MimirMissedRecordsFromKafka

当 ingester 未能处理来自 Kafka 的某些 records 时,此警报会触发。换句话说,offsets 中存在一个 gap。

工作原理

  • ingester 从 Kafka 读取 records,并按顺序处理它们。它跟踪处理的最后一个 record 的 offset。
  • 在 fetches 下一批 records 时,它会检查第一个可用 record 的 offset 是否比最后处理的 offset 大一。如果第一个可用 offset 比这大,则 ingester 未能处理某些 records。
  • Kafka 不保证顺序 offsets。如果 records 已从 Kafka 手动删除,或者 records 是在事务中生成的并且事务被中止,则可能存在一个 gap。
  • Mimir 不在事务中生成也不删除 records。
  • 当 ingester 启动时,它尝试从处理的最后一个 offset 恢复。如果 ingester 不可用时间足够长,导致下一个 record 因 retention 而已被移除,则 ingester 会未处理某些 records。

如何调查

  • 找出未处理的 offsets。ingester 会将其与消息 there is a gap in consumed offsets 一起记录。
  • 验证您的 Kafka cluster 中没有删除任何 records。
  • 验证 ingester 的停机时间是否未超过 Kafka 分区的 retention 时间。
  • 报告一个 bug。

MimirStrongConsistencyEnforcementFailed

当太多具有 strong consistency 的读取请求失败时,此警报会触发。

工作原理

  • 当读取请求要求 strong-consistency 保证时,query-frontend 从 Kafka fetches 最后生成的 offsets,并将此信息传播到 ingesters。然后,ingesters 等待直到具有请求 offset 的 record 被消费。
  • 如果 fetches 最后生成的 offsets 失败,或者在 fetches offsets 或等待 offset 被消费时读取请求超时,则认为这是具有 strong-consistency 的请求失败。ingesters 等待失败发生在请求 offset 未在配置的 -ingest-storage.kafka.wait-strong-read-consistency-timeout 时间内被消费的情况下。
  • 如果请求由于未能强制执行 strong-consistency 而持续失败,则会触发此警报。

如何调查

  • Mimir / Queries 控制面板上检查到“last produced offset”的失败和延迟。
  • Mimir / Queries 控制面板上检查具有 strong-consistency 的请求的等待延迟。
  • 检查 ingesters 是否处理太多 records,以及它们是否需要向上扩展(垂直或水平)。
  • 在 query-frontend 和/或 ingester 日志中检查实际错误,以查看是先达到 -ingest-storage.kafka.wait-strong-read-consistency-timeout 还是先达到请求超时。

MimirStrongConsistencyOffsetNotPropagatedToIngesters

当 ingesters 在未指定 offset 的情况下接收到数量意外高的 strongly consistent requests 时,此警报会触发。

工作原理

如何调查

  • 我们期望 query-frontend fetches 最后生成的 offsets,然后将其传播到 ingesters。如果未发生此情况,则可能是我们在 Mimir 中引入了一个 bug,该 bug 破坏了 offsets 从 query-frontend 到 ingester 的传播。您应该调查 Mimir 代码更改并修复它。

MimirKafkaClientBufferedProduceBytesTooHigh

当用于将传入的写入请求写入 Kafka 的 Kafka client buffer 接近满时,此警报会触发。

工作原理

  • Distributor 和 ruler 将写入请求封装到 Kafka records 中,并将其发送到 Kafka。
  • Kafka 客户端对发送到 Kafka 或已发送但尚未确认的总缓冲 records 字节大小有上限。
  • 达到上限后,Kafka 客户端停止生成更多 records 并快速失败。
  • 此上限通过 -ingest-storage.kafka.producer-max-buffered-bytes 配置。
  • 默认上限被故意配置得很高,因此当缓冲区利用率接近上限时,这表明可能存在问题。

如何调查

  • 查询 cortex_ingest_storage_writer_buffered_produce_bytes{quantile="1.0"} 指标以查看实际缓冲区利用率峰值。
    • 如果高缓冲区利用率仅限于一小部分 pods,则客户端 pods 中可能存在问题。
    • 如果高缓冲区利用率遍布所有或大多数 pods,则 Kafka 中可能存在问题。

Ingester 在从 Kafka 消费时过载

本 runbook 涵盖 ingester 在从 Kafka 接收指标数据(consuming)时过载的情况。

例如,如果写入到分区的 active series 数量超过了 ingester 容量,写入路径将继续写入该分区,但拥有该分区的 ingester 将无法接收数据。这种情况的可能症状:

工作原理

  • 一个 ingester 拥有 1 个且仅有 1 个分区。一个分区可以被多个 ingester 拥有,但每个 ingester 始终拥有一个分区。
  • 指标数据由 distributors 写入分区,写入数据量由写入路径的传入流量驱动。Distributors 不知道每个分区的负载对于将从该分区消费的 ingester 来说是否“过多”。
  • ingester 预期会 autoscale。当 ingester 中的 active series 数量增长超过扩展阈值时,将向集群添加更多 ingester。扩展 ingester 时,会添加新分区,并在分区之间重新平衡传入的指标数据。但是,旧数据(已写入分区的数据)不会移动,负载仅对扩展后接收的指标数据进行重新平衡。

如何修复

  • 垂直扩展 ingester(无数据丢失)

    • 根据饱和资源,为 ingester 添加更多 CPU/内存/磁盘。
    • 增加 ingester 最大系列实例限制(请参阅MimirIngesterReachingSeriesLimit runbook)。
  • 跳过重放分区中过载的积压数据(数据丢失)

    1. 确保 ingester 已水平扩展,并且新分区在 partitions ring 中处于 ACTIVE 状态。如果 autoscaler 尚未扩展 ingester,请手动添加更多 ingester 副本(例如,增加 HPA min replicas,或在 ingester autoscaling 被禁用时手动设置所需的 ingester 副本数量)。

    2. 找出创建新分区并在 ring 中变为 ACTIVE 状态的时间戳(例如,查看新 ingester 的日志)。

    3. 使用以下配置暂时重启 ingester

      # Set <value> to the timestamp retrieved from previous step. The timestamp should be Unix epoch with milliseconds precision.
      -ingest-storage.kafka.consume-from-position-at-startup=timestamp
      -ingest-storage.kafka.consume-from-timestamp-at-startup=<value>

      或者,如果您可以快速找到新分区在 ring 中变为 ACTIVE 状态的时间戳,您可以暂时配置 ingester 从末尾重放分区

      -ingest-storage.kafka.consume-from-position-at-startup=end
    4. 当 ingester 稳定后,恢复上一步应用的临时配置。

MimirBlockBuilderNoCycleProcessing

当 block-builder 停止报告处理过的 cycles 异常长时间时,此警报会触发。

工作原理

  • block-builder 定期从 Kafka 分区消费一部分积压数据,并将消费的数据处理成 TSDB 块。block-builder 将这些周期称为“cycles”。
  • 如果 block-builder 持续一段时间未处理任何 cycles,这可能表明某个 block-builder 实例 stuck,无法完成 cycle 处理。

如何调查

  • 检查 block-builder 日志,查看其 pods 一直在忙些什么。block-builder 会记录 start consumingdone consuming 日志消息,标记每个分区的 consume-cycles。这些日志记录包含 cycle 的详细信息、Kafka topic 的 offsets 等。据此进行故障排除。

数据恢复 / 临时缓解

虽然 block builder 仍在成熟中,但 ingester 可能仍在将块上传到 backup bucket(如果您将 bucket 命名为 *-blocks,则 backup bucket 可能是 *-ingester-blocks)。

如果 block builder 永久性地遗漏了消费一部分分区,或者存在持续的问题阻止其消费,请尝试以下步骤。

如果存在 backup *-ingester-blocks bucket

  1. 首先,重新配置 ingester 将块上传到 main *-blocks bucket。
  2. 使用 Mimir 的 copyblocks 工具将 backup bucket *-ingester-blocks 中的块复制到 main *-blocks bucket,持续时间为 block builder 未生成块的时间。建议将复制块的起始时间设置为问题开始前几小时(可能 4 小时)。
  3. 修复 block builder 中的问题。让它追赶上积压数据。追赶上后,您可以将 ingester 切换回 backup bucket。

如果 ingester 没有上传到 backup bucket

  • 增加 Kafka topic 的 retention 以争取一些时间。
  • 使用较旧版本且使用新的 kafka topic 名称启动一组新的 block builder,以免与现有的 block builder 冲突。选择未发现问题的最后一个版本;在大多数情况下,这将是导致警报的版本之前的版本。
  • 如果 block-builder.lookback-on-no-commit 未涵盖问题开始的时间,请将其设置得足够长,以便这些新的 block builder 从足够远的地方开始,以涵盖丢失的数据。
  • 如果在分区中存在导致 block builder 严重失败的损坏数据,则此解决方案将无效。继续增加 kafka topic retention,直到问题解决且 block builder 已追赶上。

MimirBlockBuilderLagging

当 block-builder 实例报告 Kafka 分区中有大量未处理的 records 时,此警报会触发。

工作原理

  • 当 block-builder 开始新的 consume cycle 时,它会检查 Kafka 分区在积压数据中有多少 records。此数量由 cortex_blockbuilder_consumer_lag_records 指标跟踪。
  • block-builder 必须消费并处理这些 records 到 TSDB 块中。
  • 在处理结束时,block-builder 将最后一个完全处理的 record 的 offset 提交到 Kafka 中。
  • 如果 block-builder 报告 lag 值很高,这可能表明某个 block-builder 实例无法完全处理和提交 Kafka record。

如何调查

  • 检查由 cortex_blockbuilder_consumer_lag_records 指标报告的每分区 lag 在过去几个小时内是否一直在增长。
  • 查看 block-builder 日志,查找在处理分区时报告的任何错误。

数据恢复 / 临时缓解:请参阅上面 MimirBlockBuilderNoCycleProcessing 的 runbook。

MimirBlockBuilderCompactAndUploadFailed

工作原理

  • block-builder 定期从 Kafka topic 消费数据,并将消费的数据处理成 TSDB 块。
  • 它会 compact 并将生成的 TSDB 块上传到 object storage。
  • 如果 block-builder 在 compact 或上传块时遇到问题,它会报告 failure metric,然后触发警报。

如何调查

  • 查看 block-builder 日志,检查存在哪些错误。

数据恢复 / 临时缓解:请参阅上面 MimirBlockBuilderNoCycleProcessing 的 runbook。

错误目录

Mimir 有一些编码的 error IDs,您可能会在 HTTP 响应或日志中看到。这些 error IDs 使您可以在接下来的文档中阅读相关详细信息。

err-mimir-missing-metric-name

当 Mimir 收到包含没有 metric name 的 series 的写入请求时,会发生此非关键错误。每个 series 必须有一个 metric name。很少会没有,在这种情况下,发送客户端中可能存在 bug。

注意

在 ingestion 期间会跳过 Invalid series,同一请求中的 valid series 会被 ingested。

err-mimir-metric-name-invalid

当 Mimir 收到包含 metric name 无效的 series 的写入请求时,会发生此非关键错误。metric name 只能包含 Prometheus 的 Metric names and labels 中定义的字符。

注意

在 ingestion 期间会跳过 Invalid series,同一请求中的 valid series 会被 ingested。

err-mimir-max-label-names-per-series

当 Mimir 收到包含 labels 数量超过配置限制的 series 的写入请求时,会发生此非关键错误。此限制旨在保护系统稳定性,防止潜在的滥用或错误。要按租户配置此限制,请使用 -validation.max-label-names-per-series 选项。

注意

在 ingestion 期间会跳过 Invalid series,同一请求中的 valid series 会被 ingested。

err-mimir-max-label-names-per-info-series

当 Mimir 收到包含 labels 数量超过配置限制的 info series 的写入请求时,会发生此非关键错误。info series 是 metric name 以 _info 结尾的 series。此限制旨在保护系统稳定性,防止潜在的滥用或错误。要按租户配置此限制,请使用 -validation.max-label-names-per-info-series 选项。

注意

在 ingestion 期间会跳过 Invalid series,同一请求中的 valid series 会被 ingested。

err-mimir-max-native-histogram-buckets

当 Mimir 收到包含 native histogram samples 且 observation buckets 数量过多的写入请求时,会发生此非关键错误。此限制旨在防止系统使用过多内存。要按租户配置此限制,请使用 -validation.max-native-histogram-buckets 选项。

注意

包含此类 samples 的 series 在 ingestion 期间会被跳过,同一请求中的 valid series 会被 ingested。

err-mimir-not-reducible-native-histogram

当 Mimir 收到包含 native histogram samples 且 observation buckets 数量过多且无法进一步减少 buckets 的写入请求时,会发生此非关键错误。由于最低分辨率 -4 的 native buckets 可以用少量 buckets 覆盖所有 64 位 float observation,这表明 -validation.max-native-histogram-buckets 选项设置得太低(<20)。

注意

包含此类 samples 的 series 在 ingestion 期间会被跳过,同一请求中的 valid series 会被 ingested。

err-mimir-invalid-native-histogram-schema

当 Mimir 收到包含 native histogram samples 且 schema number 无效的写入请求时,会发生此非关键错误。当前,有效的 schema number 范围为 [-4, 8]。

注意

包含此类 samples 的 series 在 ingestion 期间会被跳过,同一请求中的 valid series 会被 ingested。

err-mimir-native-histogram-count-mismatch

当 Mimir 收到包含 native histogram samples 且 buckets counts 与 native histogram 中记录的总 count 不符的写入请求时,会发生此非关键错误,前提是总 sum 是常规 float number。

注意

包含此类 samples 的 series 在 ingestion 期间会被跳过,同一请求中的 valid series 会被 ingested。

注意

-ingester.error-sample-rate 配置为大于 0 的值时,native histogram 无效错误仅每 -ingester.error-sample-rate 次记录一次。

err-mimir-native-histogram-count-not-big-enough

当 Mimir 收到包含 native histogram samples 且 buckets counts 之和大于 native histogram 中记录的总 count 的写入请求时,会发生此非关键错误,前提是总 sum 不是 float number (NaN)。

注意

包含此类 samples 的 series 在 ingestion 期间会被跳过,同一请求中的 valid series 会被 ingested。

注意

-ingester.error-sample-rate 配置为大于 0 的值时,native histogram 无效错误仅每 -ingester.error-sample-rate 次记录一次。

err-mimir-native-histogram-negative-bucket-count

当 Mimir 收到包含 native histogram samples 且某个 bucket count 为负的写入请求时,会发生此非关键错误。

注意

包含此类 samples 的 series 在 ingestion 期间会被跳过,同一请求中的 valid series 会被 ingested。

注意

-ingester.error-sample-rate 配置为大于 0 的值时,native histogram 无效错误仅每 -ingester.error-sample-rate 次记录一次。

err-mimir-native-histogram-span-negative-offset

当 Mimir 收到包含 native histogram samples 且 bucket span 具有负 offset 的写入请求时,会发生此非关键错误。

注意

包含此类 samples 的 series 在 ingestion 期间会被跳过,同一请求中的 valid series 会被 ingested。

注意

-ingester.error-sample-rate 配置为大于 0 的值时,native histogram 无效错误仅每 -ingester.error-sample-rate 次记录一次。

err-mimir-native-histogram-spans-buckets-mismatch

当 Mimir 收到包含 native histogram samples 且 bucket counts 数量与 bucket spans 中编码的 buckets 数量不符的写入请求时,会发生此非关键错误。

注意

包含此类 samples 的 series 在 ingestion 期间会被跳过,同一请求中的 valid series 会被 ingested。

注意

-ingester.error-sample-rate 配置为大于 0 的值时,native histogram 无效错误仅每 -ingester.error-sample-rate 次记录一次。

err-mimir-native-histogram-ooo-disabled

当 Mimir 收到包含 native histogram samples 且另一个具有更晚时间戳的 sample 已被 ingested,并且 -ingester.ooo-native-histograms-ingestion-enabled 设置为 false 时,会发生此非关键错误。

注意

包含此类 samples 的 series 在 ingestion 期间会被跳过,同一请求中的 valid series 会被 ingested。

注意

-ingester.error-sample-rate 配置为大于 0 的值时,native histogram 无效错误仅每 -ingester.error-sample-rate 次记录一次。

err-mimir-label-invalid

当 Mimir 收到包含 label name 无效的 series 的写入请求时,会发生此非关键错误。label name 只能包含 Prometheus 的 Metric names and labels 中定义的字符。

注意

在 ingestion 期间会跳过 Invalid series,同一请求中的 valid series 会被 ingested。

err-mimir-label-value-invalid

当 Mimir 收到包含 label 值无效的 series 的写入请求时,会发生此非关键错误。label 值只能包含 Prometheus 的 Metric names and labels 中定义的 unicode 字符。

注意

在 ingestion 期间会跳过 Invalid series,同一请求中的 valid series 会被 ingested。

err-mimir-label-name-too-long

当 Mimir 收到包含 label name 长度超过配置限制的 series 的写入请求时,会发生此非关键错误。此限制旨在保护系统稳定性,防止潜在的滥用或错误。要按租户配置此限制,请使用 -validation.max-length-label-name 选项。

注意

在 ingestion 期间会跳过 Invalid series,同一请求中的 valid series 会被 ingested。

err-mimir-label-value-too-long

当 Mimir 收到包含 label 值长度超过配置限制的 series 的写入请求时,会发生此非关键错误。此限制旨在保护系统稳定性,防止潜在的滥用或错误。要按租户配置此限制,请使用 -validation.max-length-label-value 选项。

注意

在 ingestion 期间会跳过 Invalid series,同一请求中的 valid series 会被 ingested。

err-mimir-duplicate-label-names

当 Mimir 收到包含同一 label name 出现两次或多次的 series 的写入请求时,会发生此非关键错误。包含重复 label name 的 series 是无效的,并在 ingestion 期间会被跳过。

注意

在 ingestion 期间会跳过 Invalid series,同一请求中的 valid series 会被 ingested。

err-mimir-labels-not-sorted

当 Mimir 收到包含 label name 未按字母顺序排序的 series 的写入请求时,会发生此错误。然而,Mimir 内部会对收到的 series 的 labels 进行排序,因此实际上不应发生此错误。如果您遇到此错误,请在 Mimir 仓库中提交 issue

注意

在 ingestion 期间会跳过 Invalid series,同一请求中的 valid series 会被 ingested。

err-mimir-too-far-in-future

当 Mimir 收到包含 sample 的 timestamp 相对于当前“真实世界”时间在未来的写入请求时,会发生此非关键错误。由于时钟偏差等原因,Mimir 接受稍微在未来的 timestamps。它拒绝根据通过 -validation.create-grace-period 选项设置的定义,在未来过远的 timestamps。可以按租户通过配置 creation_grace_period 选项来微调容差。

注意

只有包含 invalid samples 的 series 在 ingestion 期间会被跳过。同一请求中的 valid samples 仍会被 ingested。

注意

-ingester.error-sample-rate 配置为大于 0 的值时,此错误仅每 -ingester.error-sample-rate 次记录一次。

err-mimir-exemplar-too-far-in-future

当 Mimir 收到包含 exemplar 的 timestamp 相对于当前“真实世界”时间在未来的写入请求时,会发生此非关键错误。由于时钟偏差等原因,Mimir 接受稍微在未来的 timestamps。它拒绝根据通过 -validation.create-grace-period 选项设置的定义,在未来过远的 timestamps。可以按租户通过配置 creation_grace_period 选项来微调容差。

注意

只有包含 invalid samples 的 series 在 ingestion 期间会被跳过。同一请求中的 valid samples 仍会被 ingested。

err-mimir-too-far-in-past

当 Mimir 拒绝 sample,因为其 timestamp 相对于 wall clock 过远时,会发生此非关键错误。

工作原理

  • distributor 或 ingester 对传入 samples 的 timestamp 实施了一个下限,用于保护系统免受潜在滥用或错误的影响。
  • 下限由当前 wall clock 减去 out_of_order_time_window 再减去 past_grace_period 设置定义。
  • timestamp 过远过去的 samples 不会被 ingested。

如何解决

  • 确保传入 samples 的 timestamps 如此之久是有意的。
  • 如果 timestamps 是正确的,请增加 past_grace_period 设置,或将其设置为 0 以禁用限制。

注意

只有 invalid samples 在 ingestion 期间会被跳过。同一请求中的 valid samples 仍会被 ingested。

err-mimir-exemplar-too-far-in-past

当 Mimir 拒绝 exemplar,因为其 timestamp 相对于 wall clock 过远时,会发生此非关键错误。

有关详细信息和如何修复,请参阅err-mimir-too-far-in-past

err-mimir-exemplar-labels-missing

当 Mimir 收到包含没有标识相关 metric 的 label 的 exemplar 的写入请求时,会发生此非关键错误。一个 exemplar 必须至少有一个有效的 label pair,否则无法将其与任何 metric 相关联。

注意

在 ingestion 期间会跳过 Invalid exemplars,同一请求中的 valid exemplars 会被 ingested。

err-mimir-exemplar-labels-too-long

当 Mimir 收到包含 exemplar 的 labels 的组合集合大小超过限制的写入请求时,会发生此非关键错误。此限制用于保护系统稳定性,防止潜在的滥用或错误,且无法配置。

注意

在 ingestion 期间会跳过 Invalid exemplars,同一请求中的 valid exemplars 会被 ingested。

err-mimir-exemplar-timestamp-invalid

当 Mimir 收到包含没有 timestamp 的 exemplar 的写入请求时,会发生此非关键错误。一个 exemplar 必须有一个有效的 timestamp,否则无法将其与任何时间点关联。

注意

在 ingestion 期间会跳过 Invalid exemplars,同一请求中的 valid exemplars 会被 ingested。

err-mimir-metadata-missing-metric-name

当 Mimir 收到包含没有 metric name 的 metric metadata 的写入请求时,会发生此非关键错误。每个 metric metadata 必须有一个 metric name。很少会没有,在这种情况下,发送客户端中可能存在 bug。

注意

在 ingestion 期间会跳过 Invalid metrics metadata,同一请求中的 valid metadata 会被 ingested。

err-mimir-metric-name-too-long

当 Mimir 收到包含 metric name 长度超过配置限制的 metric metadata 的写入请求时,会发生此非关键错误。此限制旨在保护系统稳定性,防止潜在的滥用或错误。要按租户配置此限制,请使用 -validation.max-metadata-length 选项。

注意

在 ingestion 期间会跳过 Invalid metrics metadata,同一请求中的 valid metadata 会被 ingested。

err-mimir-unit-too-long

当 Mimir 收到包含 unit name 长度超过配置限制的 metric metadata 的写入请求时,会发生此非关键错误。此限制旨在保护系统稳定性,防止潜在的滥用或错误。要按租户配置此限制,请使用 -validation.max-metadata-length 选项。

注意

在 ingestion 期间会跳过 Invalid metrics metadata,同一请求中的 valid metadata 会被 ingested。

err-mimir-distributor-max-ingestion-rate

当 distributor 中每秒接收到的 samples, exemplars 和 metadata 的速率超过限制时,会发生此关键错误。

distributor 对每秒可以 ingested 的 samples 实施速率限制,用于在流量高的情况下保护 distributor 免于过载。此每实例限制适用于它接收到的所有 samples, exemplars 和所有 metadata。此外,此限制涵盖每个 distributor 中的所有租户。

如何解决

  • 扩展 distributor。
  • 使用 -distributor.instance-limits.max-ingestion-rate 选项增加限制。

err-mimir-distributor-max-inflight-push-requests

当 distributor 因达到最大 in-flight 请求限制而拒绝写入请求时,会发生此错误。

工作原理

  • distributor 对 in-flight 写入 (push) 请求的数量有每实例限制。
  • 此限制适用于所有 in-flight 写入请求,跨所有租户,并在流量高的情况下保护 distributor 免于过载。
  • 要配置此限制,请设置 -distributor.instance-limits.max-inflight-push-requests 选项。

如何解决

  • 通过设置 -distributor.instance-limits.max-inflight-push-requests 选项来增加限制。
  • 通过 Mimir / Writes 控制面板检查写入请求延迟,并回来调查高延迟的根本原因(延迟越高,in-flight 写入请求的数量越多)。
  • 考虑横向扩展 distributor。

err-mimir-distributor-max-inflight-push-requests-bytes

当 distributor 因所有 in-flight 请求的总字节大小达到限制而拒绝写入请求时,会发生此错误。

工作原理

  • distributor 对所有 in-flight 写入 (push) 请求的总字节大小有每实例限制。
  • 此限制适用于所有 in-flight 写入请求,跨所有租户,并在写入路径流量高或延迟高的情况下保护 distributor 免于内存不足。
  • 要配置此限制,请设置 -distributor.instance-limits.max-inflight-push-requests-bytes 选项。

如何解决

  • 通过设置 -distributor.instance-limits.max-inflight-push-requests-bytes 选项来增加限制。
  • 通过 Mimir / Writes 控制面板检查写入请求延迟,并回来调查请求大小增加或延迟增加的根本原因(延迟越高,in-flight 写入请求的数量越多,它们的组合大小就越大)。
  • 考虑横向扩展 distributor。

err-mimir-ingester-max-ingestion-rate

当 ingester 中每秒接收到的 samples 的速率超过限制时,会发生此关键错误。

ingester 对每秒可以 ingested 的 samples 实施速率限制,用于在流量高的情况下保护 ingester 免于过载。此每实例限制适用于它接收到的所有 samples。此外,此限制涵盖每个 ingester 中的所有租户。

如何解决

  • 扩展 ingester。
  • 使用 -ingester.instance-limits.max-ingestion-rate 选项(或 runtime config 中的 max_ingestion_rate)增加限制。

err-mimir-ingester-max-tenants

当 ingester 收到针对新租户(尚未存储任何 series 的租户)的写入请求,但因达到每个 ingester 允许的最大租户数量而无法接受时,会发生此关键错误。

如何解决

  • 使用 -ingester.instance-limits.max-tenants 选项(或 runtime config 中的 max_tenants)增加限制。
  • 考虑配置 ingester shuffle sharding 以减少每个 ingester 的租户数量。

err-mimir-ingester-max-series

当 ingester 因达到内存中 series 的最大数量而拒绝写入请求时,会发生此关键错误。

工作原理

  • ingester 将最新 series 数据保存在内存中。
  • ingester 对内存中 series 的数量有每实例限制,用于在流量高的情况下保护 ingester 免于过载。
  • 达到内存中 series 的数量限制时,新 series 会被拒绝,而 samples 仍可以附加到现有 series 中。
  • 要配置此限制,请设置 -ingester.instance-limits.max-series 选项(或 runtime config 中的 max_series)。

如何解决

err-mimir-ingester-max-inflight-push-requests

当 ingester 因达到最大 in-flight 请求限制而拒绝写入请求时,会发生此错误。

工作原理

  • ingester 对 in-flight 写入 (push) 请求的数量有每实例限制。
  • 此限制适用于所有 in-flight 写入请求,跨所有租户,并在流量高的情况下保护 ingester 免于过载。
  • 要配置此限制,请设置 -ingester.instance-limits.max-inflight-push-requests 选项(或 runtime config 中的 max_inflight_push_requests)。

如何解决

  • 通过设置 -ingester.instance-limits.max-inflight-push-requests 选项(或 runtime config 中的 max_inflight_push_requests)来增加限制。
  • 通过 Mimir / Writes 控制面板检查写入请求延迟,并回来调查高延迟的根本原因(延迟越高,in-flight 写入请求的数量越多)。
  • 考虑横向扩展 ingester。

err-mimir-ingester-max-inflight-push-requests-bytes

当 ingester 因所有 in-flight push 请求的最大大小达到限制而拒绝写入请求时,会发生此错误。

工作原理

  • ingester 对 in-flight 写入 (push) 请求的总大小有每实例限制。
  • 此限制适用于所有 in-flight 写入请求,跨所有租户,并在流量高的情况下保护 ingester 免于因传入请求而使用过多内存。
  • 要配置此限制,请设置 -ingester.instance-limits.max-inflight-push-requests-bytes 选项(或 runtime config 中的 max_inflight_push_requests_bytes)。

如何解决

  • 如果可能,通过设置 -ingester.instance-limits.max-inflight-push-requests-bytes 选项(或 runtime config 中的 max_inflight_push_requests_bytes)来增加限制。
  • 通过 Mimir / Writes 控制面板检查写入请求延迟,并回来调查高延迟的根本原因(延迟越高,in-flight 写入请求的数量越多)。
  • 考虑横向扩展 ingester。

err-mimir-ingester-max-inflight-read-requests

当 ingester 因达到最大 in-flight 请求限制而拒绝读取请求时,会发生此错误。

工作原理

  • ingester 对 in-flight 读取请求的数量有每实例限制。
  • 此限制适用于所有 in-flight 读取请求,跨所有租户,并在流量高的情况下保护 ingester 免于过载。
  • 要配置此限制,请设置 -ingester.read-reactive-limiter 选项。

如何解决

  • 通过 Mimir / Reads 控制面板检查读取请求延迟,并回来调查高延迟的根本原因(延迟越高,in-flight 读取请求的数量越多)。
  • 考虑横向扩展 ingester。

err-mimir-max-series-per-user

当给定租户的内存中 series 数量超过配置限制时,会发生此错误。

此限制用于在租户写入大量 series 时保护 ingester 免于过载,同时保护整个系统的稳定性,防止潜在的滥用或错误。要按租户配置此限制,请使用 -ingester.max-global-series-per-user 选项(或 runtime configuration 中的 max_global_series_per_user)。

如何解决

  • 确保受影响租户写入的实际 series 数量是合法的。
  • 考虑使用 -ingester.max-global-series-per-user 选项(或 runtime configuration 中的 max_global_series_per_user)增加 per-tenant 限制。

注意

-ingester.error-sample-rate 配置为大于 0 的值时,此错误仅每 -ingester.error-sample-rate 次记录一次。

err-mimir-max-series-per-metric

当给定租户和 metric name 的内存中 series 数量超过配置限制时,会发生此错误。

此限制主要用于保护租户免受其 metrics instrumentation 的潜在错误。例如,如果一个被检测的应用暴露一个 metric,其 label 值包含非常动态的数据(例如 timestamp),则该 metric 的 ingestion 将很快达到 per-tenant series 限制,导致其他 metrics 也被拒绝。此限制对每个 metric name 可以拥有的最大 series 数量设置了一个上限,在达到 per-tenant series 限制之前,仅拒绝该 metric name 的超出 series。要按租户配置此限制,请使用 -ingester.max-global-series-per-metric 选项(或 runtime configuration 中的 max_global_series_per_metric)。

如何解决

  • 检查错误消息中的详细信息,找出受影响的 metric name。
  • 调查受影响 metric name 暴露的大量 series 是否合法。
  • 考虑通过调整或移除其部分 labels 来降低受影响 metric 的 cardinality。
  • 考虑使用 -ingester.max-global-series-per-metric 选项增加 per-tenant 限制。
  • 考虑使用 -ingester.ignore-series-limit-for-metric-names 选项(或 runtime configuration 中的 max_global_series_per_metric)从此限制的检查中排除特定的 metric name。

注意

-ingester.error-sample-rate 配置为大于 0 的值时,此错误仅每 -ingester.error-sample-rate 次记录一次。

err-mimir-max-metadata-per-user

当给定租户的内存中带有 metadata 的 metrics 数量超过配置限制时,会发生此非关键错误。

Metric metadata 是一组附加到 metric name 的信息,例如其 unit(例如 counter)和 description。发送方可以在写入请求中包含 Metric metadata,并在查询 /api/v1/metadata API endpoint 时返回。Metric metadata 存储在 ingester 内存中,因此存储的 metric metadata 数量越多,内存利用率越高。

Mimir 对具有 metadata 的 metric name 数量有 per-tenant 限制。此限制用于保护整个系统的稳定性,防止潜在的滥用或错误。要按租户配置此限制,请使用 -ingester.max-global-series-per-user 选项(或 runtime configuration 中的 max_global_metadata_per_user)。

如何解决

  • 运行 instant query count(count by(__name__) ({__name__=~".+"})) 检查受影响租户的当前 metric name 数量。或者,您可以调用 API endpoint /api/v1/cardinality/label_names 获取 __name__ label 的 cardinality。
  • 考虑将 per-tenant 限制设置增加到大于前一次查询返回的唯一 metric name 数量的值。

注意

-ingester.error-sample-rate 配置为大于 0 的值时,此错误仅每 -ingester.error-sample-rate 次记录一次。

err-mimir-max-metadata-per-metric

当给定 metric name 的不同 metadata 数量超过配置限制时,会发生此非关键错误。

Metric metadata 是一组附加到 metric name 的信息,例如其 unit(例如 counter)和 description。通常,对于给定的 metric name,只有一组 metadata(例如,不同应用暴露的同一 metric name 具有相同的 counter 和 description)。但是,在某些 edge cases 下,同一 metric name 在不同应用之间可能具有不同的含义,或含义相同但 description 略有不同。在这些 edge cases 下,不同应用会为同一 metric name 暴露不同的 metadata。

此限制用于保护整个系统的稳定性,防止潜在的滥用或错误,以防给定 metric name 的 metadata 变体数量无限增长。要按租户配置此限制,请使用 -ingester.max-global-series-per-metric 选项(或 runtime configuration 中的 max_global_metadata_per_metric)。

如何解决

  • 查询 API endpoint /api/v1/metadata?metric=<name>(将 <name> 替换为 metric name)检查受影响 metric name 的 metadata。
  • 如果不同的 metadata 是意外的,请考虑修复被检测应用中的差异。
  • 如果不同的 metadata 是预期的,请考虑使用 -ingester.max-global-series-per-metric 选项(或 runtime configuration 中的 max_global_metadata_per_metric)增加 per-tenant 限制。

注意

-ingester.error-sample-rate 配置为大于 0 的值时,此错误仅每 -ingester.error-sample-rate 次记录一次。

err-mimir-max-chunks-per-query

当查询执行超出了 fetches 的 series chunks 数量限制时,会发生此错误。

此限制用于保护系统稳定性,防止运行 fetches 大量数据的查询时潜在的滥用或错误。要全局配置此限制,请使用 -querier.max-fetched-chunks-per-query 选项。要按租户配置此限制,请在 runtime configuration 中设置 max_fetched_chunks_per_query per-tenant override。

如何解决

  • 考虑缩短查询的时间范围和/或降低 cardinality。要降低查询的 cardinality,您可以在查询中添加更多 label matchers,限制匹配 series 的集合。
  • 考虑使用 -querier.max-fetched-chunks-per-query 选项增加全局限制。
  • 考虑在 runtime configuration 中使用 max_fetched_chunks_per_query per-tenant override 按租户增加限制。

err-mimir-max-estimated-chunks-per-query

当查询执行超出预计 fetches 的 series chunks 数量限制时,会发生此错误。

此估计基于将从 ingester 发送到 querier 的实际 chunks 数量,以及将从 store-gateway 发送到 querier 的 chunks 数量估计。

此限制用于保护系统稳定性,防止运行 fetches 大量数据的查询时潜在的滥用或错误。要全局配置此限制,请使用 -querier.max-estimated-fetched-chunks-per-query-multiplier 选项。要按租户配置此限制,请在 runtime configuration 中设置 max_estimated_fetched_chunks_per_query_multiplier per-tenant override。

如何解决

  • 考虑缩短查询的时间范围和/或降低 cardinality。要降低查询的 cardinality,您可以在查询中添加更多 label matchers,限制匹配 series 的集合。
  • 考虑使用 -querier.max-estimated-fetched-chunks-per-query-multiplier 选项增加全局限制。
  • 考虑在 runtime configuration 中使用 max_estimated_fetched_chunks_per_query_multiplier per-tenant override 按租户增加限制。

err-mimir-max-series-per-query

当查询执行超出最大 series 数量限制时,会发生此错误。

此限制用于保护系统稳定性,防止运行 fetches 大量数据的查询时潜在的滥用或错误。要全局配置此限制,请使用 -querier.max-fetched-series-per-query 选项。要按租户配置此限制,请在 runtime configuration 中设置 max_fetched_series_per_query per-tenant override。

如何解决

  • 考虑缩短查询的时间范围和/或降低 cardinality。要降低查询的 cardinality,您可以在查询中添加更多 label matchers,限制匹配 series 的集合。
  • 考虑使用 -querier.max-fetched-series-per-query 选项增加全局限制。
  • 考虑在 runtime configuration 中使用 max_fetched_series_per_query per-tenant override 按租户增加限制。

err-mimir-max-chunks-bytes-per-query

当查询执行超出 fetches 的 chunks 聚合大小(以字节为单位)限制时,会发生此错误。

此限制用于保护系统稳定性,防止运行 fetches 大量数据的查询时潜在的滥用或错误。要全局配置此限制,请使用 -querier.max-fetched-chunk-bytes-per-query 选项。要按租户配置此限制,请在 runtime configuration 中设置 max_fetched_chunk_bytes_per_query per-tenant override。

如何解决

  • 考虑缩短查询的时间范围和/或降低 cardinality。要降低查询的 cardinality,您可以在查询中添加更多 label matchers,限制匹配 series 的集合。
  • 考虑使用 -querier.max-fetched-chunk-bytes-per-query 选项增加全局限制。
  • 考虑在 runtime configuration 中使用 max_fetched_chunk_bytes_per_query per-tenant override 按租户增加限制。

err-mimir-max-estimated-memory-consumption-per-query

当查询执行超出单个查询消耗的最大估计内存限制时,会发生此错误。

此限制用于保护系统稳定性,防止运行 fetches 大量数据的查询时潜在的滥用或错误。此限制仅在使用 Mimir 的 query engine 时适用(即 -querier.query-engine=mimir)。要全局配置此限制,请使用 -querier.max-estimated-memory-consumption-per-query 选项。要按租户配置此限制,请在 runtime configuration 中设置 max_estimated_memory_consumption_per_query per-tenant override。

如何解决

  • 考虑缩短查询的时间范围。
  • 考虑降低查询的 cardinality。要降低查询的 cardinality,您可以在查询中添加更多 label matchers,限制匹配 series 的集合。
  • 考虑对查询应用聚合函数,例如 sumavg
  • 考虑使用 -querier.max-estimated-memory-consumption-per-query 选项增加全局限制。
  • 考虑在 runtime configuration 中使用 max_estimated_memory_consumption_per_query per tenant-override 按租户增加限制。

err-mimir-max-query-length

当部分查询(在 query-frontend 可能进行 splitting, sharding 之后)的时间范围超过配置的最大长度时,会发生此错误。有关总查询长度的限制,请参阅err-mimir-max-total-query-length

PromQL instant 和 range queries 都可以 fetches 一段时间内的 metrics 数据。range query 需要一个 startend timestamp,因此 end 减去 start 的差值是查询的时间范围长度。instant query 需要一个 time 参数,并且查询在该时间点 fetches samples 执行。然而,即使是 instant query 也可以通过使用 range vector selectors fetches 一段时间内的 metrics 数据。例如,instant query sum(rate(http_requests_total{job="prometheus"}[1h])) fetches 1 小时内的 metrics。这段时间就是 Grafana Mimir 所称的查询时间范围长度(或查询长度)。

Mimir 对查询长度有上限。此限制应用于 partial queries,在它们被 query-frontend 按时间 split 后。此限制旨在保护系统稳定性,防止潜在的滥用或错误。要按租户配置此限制,请使用 -querier.max-partial-query-length 选项(或 runtime configuration 中的 max_partial_query_length)。

err-mimir-max-total-query-length

当查询的时间范围超过配置的最大长度时,会发生此错误。有关 partial query 长度的限制(在按 interval 和/或 sharding 进行查询 splitting 之后),请参阅err-mimir-max-query-length

PromQL range queries 可以 fetches 一段时间内的 metrics 数据。range query 需要一个 startend timestamp,因此 end 减去 start 的差值是查询的时间范围长度。

Mimir 对查询长度有上限。此限制应用于 range queries,在它们被 query-frontend 按时间 split 或 sharded 之前。此限制旨在保护系统稳定性,防止潜在的滥用或错误。要按租户配置此限制,请使用 -query-frontend.max-total-query-length 选项(或 runtime configuration 中的 max_total_query_length)。

err-mimir-max-query-expression-size-bytes

当原始查询的大小超过配置的最大大小(以字节为单位)时,会发生此错误。

此限制用于保护系统稳定性,防止运行潜在的大型昂贵查询时潜在的滥用或错误。要按租户配置此限制,请使用 -query-frontend.max-query-expression-size-bytes 选项(或 runtime configuration 中的 max_query_expression_size_bytes)。

如何解决

  • 考虑减小查询的大小。可能有更简单的方法来选择所需的数据,或者从 Mimir 导出数据的更好方法。
  • 考虑使用 -query-frontend.max-query-expression-size-bytes 选项(或 runtime configuration 中的 max_query_expression_size_bytes)增加 per-tenant 限制。

err-mimir-tenant-max-request-rate

当此租户每秒写入请求的速率超过限制时,会发生此错误。

工作原理

  • 对此租户每秒写入请求存在 per-tenant 速率限制,并应用于此租户的所有 distributor。
  • 此限制使用 token buckets 实现。

如何解决

  • 使用 -distributor.request-rate-limit(每秒请求数)和 -distributor.request-burst-size(请求数量)选项(或 runtime configuration 中的 request_raterequest_burst_size)增加 per-tenant 限制。可配置的 burst 表示在短时流量高峰的情况下,有多少请求可以暂时超出限制。配置的 burst 大小必须大于或等于配置的限制。

err-mimir-tenant-max-ingestion-rate

当此租户每秒接收到的 samples, exemplars 和 metadata 的速率超过限制时,会发生此错误。

工作原理

  • 对此租户每秒可以 ingested 的 samples, exemplars 和 metadata 存在 per-tenant 速率限制,并应用于此租户的所有 distributor。
  • 此限制使用 token buckets 实现。

如何解决

  • 使用 -distributor.ingestion-rate-limit(每秒 samples 数)和 -distributor.ingestion-burst-size(samples 数量)选项(或 runtime configuration 中的 ingestion_rateingestion_burst_size)增加 per-tenant 限制。可配置的 burst 表示在短时流量高峰的情况下,有多少 samples, exemplars 和 metadata 可以暂时超出限制。配置的 burst 大小必须大于或等于配置的限制。

err-mimir-tenant-too-many-ha-clusters

当 distributor 因 high-availability (HA) clusters 数量达到此租户的配置限制而拒绝写入请求时,会发生此错误。

工作原理

  • distributor 对 HA tracker 为单个租户跟踪的集群数量实施了一个上限。
  • 当写入请求会添加一个新集群,而该租户当前拥有的数量已经等于限制时,此错误会被触发。
  • 要配置此限制,请设置 -distributor.ha-tracker.max-clusters 选项(或 runtime configuration 中的 ha_max_clusters)。

如何解决

  • 使用 -distributor.ha-tracker.max-clusters 选项(或 runtime configuration 中的 ha_max_clusters)增加 per-tenant 限制。

err-mimir-sample-timestamp-too-old

当 ingester 因 sample 的 timestamp 相对于同一租户所有 time series 中收到的最新 timestamp 过旧而拒绝 sample 时,会发生此错误。

工作原理

  • 如果传入 timestamp 比为租户 ingested 的最新 timestamp 旧 1 小时以上,则 sample 将被拒绝。

注意

如果启用 out-of-order sample ingestion,则此错误类似于下面的 err-mimir-sample-out-of-order,区别在于 sample 相对于特定 time series 或 TSDB 的最新 sample,比 out-of-order time window 更旧。

注意

-ingester.error-sample-rate 配置为大于 0 的值时,此错误仅每 -ingester.error-sample-rate 次记录一次。

err-mimir-sample-out-of-order

当 ingester 因另一个具有更晚 timestamp 的 sample 已被 ingested 而拒绝 sample 时,会发生此错误。

工作原理

  • 目前,对于给定的 series,不允许 samples out of order 被 ingested。

常见原因

  • 您的代码有一个 target,它多次暴露相同的 time series,或多个具有相同 labels 的 targets。
  • 您的 Prometheus 实例的系统时间已向后调整。如果这是个错误,请将系统时间调回正常。否则,等待系统时间追赶到更改的时间。要测量 target 节点的时钟偏差,可以使用 timex metrics,例如 node_timex_maxerror_secondsnode_timex_estimated_error_seconds
  • 您正在运行多个 Prometheus 实例 pushes 相同的 metrics,并且您的 high-availability tracker 未正确配置进行 deduplication
  • Prometheus relabelling 已配置,并且在 relabelling 后导致 series 冲突。检查错误消息以获取关于哪个 series 收到 out of order sample 的信息。
  • 一个 Prometheus 实例已重启,并在重启时将其 Write-Ahead Log 中的所有数据 pushes 到 remote write,其中一些数据已经被 pushes 和 ingested。这是正常的,可以忽略。
  • Prometheus 和 Mimir 具有相同的 recording rule,这在两处生成完全相同的 series,并导致 remote write 或 rule evaluation 随机失败,具体取决于 timing。

注意

您可以在博客文章 Debugging out of order samples 中了解更多关于 Prometheus 中 out of order samples 的信息。

注意

-ingester.error-sample-rate 配置为大于 0 的值时,此错误仅每 -ingester.error-sample-rate 次记录一次。

err-mimir-sample-duplicate-timestamp

当 ingester 因 sample 与同一 time series 中先前收到的具有相同 timestamp 但不同 value 的 sample 重复而拒绝 sample 时,会发生此错误。

常见原因

  • 多个 endpoint 正在导出相同的 metrics,或者多个 Prometheus 实例正在 scraping 具有相同 labels 的不同 metrics。
  • Prometheus relabelling 已配置,并且在 relabelling 后导致 series 冲突。检查错误消息以获取关于哪个 series 收到 duplicate sample 的信息。
  • 如果 ruler 在写入 ALERTS_FOR_STATE metric 时记录此错误,这可能是由多个具有相同 alert name 和 labels 的 alerting rule 同时触发引起的。检查错误消息中提到的 alert name 是否定义了多次,如果这是有意的,请确保每个 alert rule 生成具有唯一 labels 的 alerts。

注意

-ingester.error-sample-rate 配置为大于 0 的值时,此错误仅每 -ingester.error-sample-rate 次记录一次。

err-mimir-exemplar-series-missing

当 ingester 因 exemplar 的相关 series 尚未被 ingested 而拒绝 exemplar 时,会发生此错误。

工作原理

  • 在 exemplar 可以被 appended 之前,series 必须已经存在,因为我们不会在 ingesting exemplar 时创建新的 series。当该 series 的 sample 被 ingested 时,series 将被创建。

err-mimir-store-consistency-check-failed

当 querier 在多次重试并连接到不同的 store-gateway 后无法 fetches 某些预期的 blocks 时,会发生此错误。查询失败是因为查询的 store-gateway 中缺少某些 blocks。

工作原理

  • Mimir 被设计用于保证查询结果的正确性,绝不返回部分查询结果。要么查询成功返回完全一致的结果,要么失败。
  • Querier 和以“internal”评估模式运行的 ruler 会运行一致性检查,以确保所有预期 blocks 已通过 store-gateway 从 long-term storage 查询。
  • 如果任何预期 blocks 未通过 store-gateway 查询,则查询将因此错误而失败。
  • 要了解更多信息,请参阅Anatomy of a query request

如何解决

err-mimir-bucket-index-too-old

当查询因 bucket index 过旧而失败时,会发生此错误。

工作原理

  • Compactor 定期向 object storage 写入一个 per-tenant 文件,称为“bucket index”。bucket index 包含给定租户的所有已知 blocks,并每 -compactor.cleanup-interval 更新一次。
  • 执行查询时,querier 和以“internal”评估模式运行的 ruler 会查找 bucket index,以找到应该通过 store-gateway 查询哪些 blocks。
  • 为确保查询所有必需的 blocks,querier 和 ruler 会根据 compactor 最后一次更新 bucket index 的时间来确定 bucket index 的年龄。
  • 如果年龄大于通过 -blocks-storage.bucket-store.bucket-index.max-stale-period 配置的最大 stale period,则查询失败。
  • 此断路器可确保 querier 和 ruler 不会由于 long-term storage 的 stale view 而返回任何部分查询结果。

如何解决

  • 确保 compactor 运行成功(例如,未崩溃,未内存不足)。
  • 确保每个 compactor 副本在 -compactor.cleanup-interval 的两倍时间内成功更新了每个拥有租户的 bucket index(以下查询假设 cleanup interval 设置为 15 分钟):time() - cortex_compactor_block_cleanup_last_successful_run_timestamp_seconds > 2 * (15 * 60)

err-mimir-distributor-max-write-message-size

当 distributor 因写入请求的消息大小大于允许的限制而拒绝写入请求时,会发生此错误。

工作原理

  • distributor 对传入写入请求的消息大小实施上限。
  • 要配置此限制,请设置 -distributor.max-recv-msg-size 选项。

如何解决

  • 使用 -distributor.max-recv-msg-size 选项增加允许的限制。

err-mimir-distributor-max-otlp-request-size

当 distributor 因 OTel 写入请求的消息大小在解压前或解压后大于允许的限制而拒绝 OTel 写入请求时,会发生此错误。

工作原理

  • distributor 对传入 OTel 写入请求的消息大小在解压前和解压后(无论压缩类型如何)实施上限。有关详细信息,请参阅 OTLP collector compression details
  • -distributor.max-otlp-request-size 设置中配置此限制。

如何解决

  • 如果您在 OTLP collector 中使用 batch processor,请在 send_batch_max_size 设置中减小最大 batch 大小。有关详细信息,请参阅 Batch Collector
  • -distributor.max-otlp-request-size 设置中增加允许的限制。

err-mimir-distributor-max-write-request-data-item-size

此错误仅在启用实验性 ingest storage 时可能返回,是由包含大于允许限制的 timeseries 或 metadata 条目的写入请求引起的。

工作原理

  • distributor 将写入请求 sharding 到 N 个分区,其中 N 是租户分区 shard size。
  • 对于每个分区,写入请求数据被编码到一个或多个 Kafka records 中。
  • Kafka record 的最大大小是 hardcoded 的,因此 per-partition 写入请求数据会自动 split 为多个 Kafka records,以便 ingested 大型写入请求。
  • 单个 timeseries 或 metadata 是最小的可 split 单位,这意味着单个 timeseries 或 metadata 条目不能 split 为多个 Kafka records。
  • 如果写入请求包含单个 timeseries 或 metadata 条目,其大小大于 Kafka record size limit,则写入请求的 ingestion 将失败,distributor 将返回 4xx HTTP status code。使用 4xx status code 可确保客户端不会重试将持续失败的请求。

如何解决

  • 配置客户端 remote writing 到 Mimir 发送较小的写入请求。

err-mimir-query-blocked

当 query-frontend 因查询至少匹配 limits 中定义的一个规则而阻止读取请求时,会发生此错误。

工作原理

  • query-frontend 实现了一个 middleware,负责评估查询是否被阻止。
  • 要配置此限制,请在 limits 中设置 blocked_queries 块。

如何解决

此错误仅在管理员明确为给定租户定义了 blocked list 时发生。在评估阻止一个或多个查询的原因后,您可以更新租户的 limits 并移除 pattern。

err-mimir-request-blocked

当 query-frontend 因 HTTP 请求至少匹配 limits 中定义的一个规则而阻止 HTTP 请求时,会发生此错误。

工作原理

  • query-frontend 实现了一个 checker,负责评估请求是否被阻止。
  • 要配置此限制,请在 limits 中设置 blocked_requests 块。

如何解决

此错误仅在管理员明确为给定租户定义了 blocked list 时发生。在评估阻止一个或多个请求的原因后,您可以更新租户的 limits 并移除 configuration。

err-mimir-alertmanager-max-grafana-config-size

当 Alertmanager 收到大于配置大小限制的 Grafana Alertmanager configuration 时,会发生此非关键错误。此限制旨在保护系统稳定性,防止潜在的滥用或错误。要按租户配置此限制,请使用 alertmanager.max-grafana-config-size-bytes 选项。

err-mimir-alertmanager-max-grafana-state-size

当 Alertmanager 收到大于配置大小限制的 Grafana Alertmanager state 时,会发生此非关键错误。此限制旨在保护系统稳定性,防止潜在的滥用或错误。要按租户配置此限制,请使用 alertmanager.max-grafana-state-size-bytes 选项。

Mimir 按 path 路由

写入路径 (Write path):

  • /distributor.Distributor/Push
  • /cortex.Ingester/Push
  • api_v1_push
  • api_v1_push_influx_write
  • otlp_v1_metrics

读取路径 (Read path):

  • /schedulerpb.SchedulerForFrontend/FrontendLoop
  • /cortex.Ingester/QueryStream
  • /cortex.Ingester/QueryExemplars
  • /gatewaypb.StoreGateway/Series
  • api_prom_api_v1_label_name_values
  • api_prom_api_v1_labels
  • api_prom_api_v1_metadata
  • api_prom_api_v1_query
  • api_prom_api_v1_query_exemplars
  • api_prom_api_v1_query_range
  • api_prom_api_v1_rules
  • api_prom_api_v1_series

规则器 / 规则路径:

  • api_v1_rules
  • api_v1_rules_namespace
  • prometheus_api_v1_rules
  • prometheus_rules_namespace
  • prometheus_rules

Mimir 块存储 - 出现问题时应如何处理

从潜在的数据丢失事件中恢复

在事件期间可能丢失的已摄取序列数据可以存储在两个位置

  1. 摄取器 (在块发送到存储桶之前)
  2. 存储桶

可能导致潜在数据丢失的根本原因有多种。在本文档中,我们将分享一些可在事件期间用作指导的通用步骤。

暂停 Compactor

即使 Compactor 未运行,Mimir 集群仍能成功运行,但长时间(12 小时以上)这将导致查询性能下降。Compactor 可能导致数据丢失,原因如下:

  • 它将块标记为删除(软删除)。这不会立即删除任何内容,但标记为删除的块在延迟过期后将被硬删除。
  • 它会在 -compactor.deletion-delay 时间后永久删除标记为删除的块(硬删除)
  • 它可能生成损坏的压缩块(例如,由于错误或源块已损坏且自动检查无法检测到)

如果您怀疑 Compactor 可能是数据丢失的原因,请暂停它(删除 StatefulSet 或将其副本缩减到 0)。您可以随时稍后重新启动它。

当 Compactor 暂停

  • 不会压缩新的块
  • 不会删除任何块(软删除和硬删除)

从摄取器中恢复源块

摄取器在其持久磁盘上保留从 TSDB head 压缩的块,直到 -blocks-storage.tsdb.retention-period 保留期过期。

如果 Compactor 生成了损坏的块,并且从摄取器上传的源块已从存储桶中硬删除,则可以使用摄取器中保留的块。

如何手动将摄取器中的块上传到存储桶

  1. 确保 Mimir pod 中已安装 gsutil。如果未安装,安装它
  2. 运行 cd /data/tsdb && /path/to/gsutil -m rsync -n -r -x 'thanos.shipper.json|chunks_head|wal' . gs://<bucket>/recovered/
    • -n 启用试运行(验证输出符合您的预期后移除它)
    • -m 启用并行模式
    • -r 启用递归 rsync
    • -x <pattern> 从同步中排除特定模式(WAL 或 shipper 元数据文件不应上传到存储桶)
    • 不要使用 -d(危险),因为它会从存储桶中删除本地文件系统中不存在的任何块

冻结摄取器持久磁盘

存储在摄取器持久磁盘中的块和 WAL 是处理未发送到存储桶的块或存储桶中损坏的块事件的最后一道防线。如果摄取器磁盘中的数据完整性面临风险(例如,接近达到 TSDB 保留期或接近达到最大磁盘利用率),您应该通过创建磁盘快照来冻结它。

创建 GCP Persistent Disk 快照

  1. 确定要创建快照的卷的 Kubernetes PVC 卷名(kubectl get pvc --namespace <namespace>
  2. 对于每个卷,从 GCP 控制台创建快照文档

暂停摄取器

暂停摄取器应作为最后手段,因为它会产生副作用。要在保留其磁盘且不中断集群写入路径的情况下暂停摄取器,您需要:

  1. 创建第二个摄取器池
  • 使用函数 newIngesterStatefulSet(), newIngesterPdb()
  1. 等待第二个池启动并运行
  2. 暂停现有摄取器(缩减到 0 或删除其 StatefulSet)

但是,由于所有尚未压缩成块的已摄取样本,查询将返回部分数据

手动步骤

使用 Kubernetes 调整持久卷大小

这是如何调整 Kubernetes 持久卷大小的详细文档的简短版本。

先决条件:

  • 运行 Kubernetes v1.11 或更高版本
  • PV 存储类具有 allowVolumeExpansion: true
  • PV 由支持的块存储卷(例如,GCP-PD、AWS-EBS 等)支持

如何增加卷大小:

  1. 编辑要调整大小的卷的 PVC(持久卷声明)spec,并增加 resources > requests > storage
  2. 重启附加到存储请求已增加的 PVC 的 pod

如何创建克隆卷 (Google Cloud 特定)

在某些场景下,保留当前卷状态以便检查同时继续使用该卷可能很有用。Google Persistent Disk 支持“克隆”操作,可用于实现此目的。新克隆的磁盘独立于其原始磁盘,可以通过将其附加到新的虚拟机/Pod 进行进一步调查。

在使用 Kubernetes 时,这里是创建指向新磁盘克隆(本例中为 clone-pvc-80cc0efa-4996-11ea-ba79-42010a96008c)的 PV(clone-ingester-7-pv),指向 PV 的 PVC(clone-ingester-7-pvc),以及最终使用 PVC 访问磁盘的 Pod(clone-ingester-7-dataaccess)的 YAML 文件。

yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: clone-ingester-7-pv
spec:
  accessModes:
    - ReadWriteOnce
  capacity:
    storage: 150Gi
  gcePersistentDisk:
    fsType: ext4
    pdName: clone-pvc-80cc0efa-4996-11ea-ba79-42010a96008c
  persistentVolumeReclaimPolicy: Retain
  storageClassName: fast
  volumeMode: Filesystem
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: clone-ingester-7-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 150Gi
  storageClassName: fast
  volumeName: clone-ingester-7-pv
  volumeMode: Filesystem
---
apiVersion: v1
kind: Pod
metadata:
  name: clone-ingester-7-dataaccess
spec:
  containers:
    - name: alpine
      image: alpine:latest
      command: ["sleep", "infinity"]
      volumeMounts:
        - name: mypvc
          mountPath: /data
      resources:
        requests:
          cpu: 500m
          memory: 1024Mi
  volumes:
    - name: mypvc
      persistentVolumeClaim:
        claimName: clone-ingester-7-pvc

准备完成后,您可以使用 kubectl exec --tty=false --stdin=false clone-ingester-7-dataaccess /bin/sh 来检查挂载在 /data 下的磁盘。

在 Mimir pod 中安装 gsutil

  1. 安装 python

    apk add python3 py3-pip
    ln --symbolic /usr/bin/python3 /usr/bin/python
    pip install google-compute-engine
  2. 下载 gsutil

    wget https://storage.googleapis.com/pub/gsutil.tar.gz
    tar -zxvf gsutil.tar.gz
    ./gsutil/gsutil --help
  3. 配置凭据

    # '-e' prompt for service account credentials.
    gsutil config -e
    
    # Private key path: /var/secrets/google/credentials.json
    # Project ID: your google project ID

删除或缩减具有持久卷的 StatefulSet

当您删除或缩减其 pod 具有持久卷声明 (PVC) 的 Kubernetes StatefulSet 时,默认情况下不会自动删除未使用的 PVC。这意味着如果 StatefulSet 被重新创建或再次扩容,已经存在 PVC 的 pod 将挂载之前使用的卷。

然而,从 Kubernetes 1.27 开始,这种行为可以改变。如果 spec.persistentVolumeClaimRetentionPolicy.whenScaled 设置为 Delete,则在缩减 StatefulSet 时将删除未使用的 PVC。同样,如果 spec.persistentVolumeClaimRetentionPolicy.whenDeleted 设置为 Delete,则在删除 StatefulSet 时将删除所有 PVC。请注意,这两种行为在 StatefulSet 扩容、执行滚动更新或 pod 在节点之间转移时都不适用。

删除 PVC 时,与其绑定的持久卷 (PV) 的处理取决于其回收策略

  • Retain: 卷不会自动删除,需要手动删除
  • Delete: 卷将自动删除

PV 的初始回收策略由其关联的存储类定义。但是,一旦创建了 PV,可以随时更改 PV 的回收策略,允许在 PVC 删除后保留它以供进一步检查。例如,如果 StatefulSet 的 spec.persistentVolumeClaimRetentionPolicy.whenScaled 设置为 Delete 并且 PV 的回收策略设置为 Delete,但您希望保留在缩减 StatefulSet 时将被移除的 pod 的 PV,则应在缩减 StatefulSet 之前将受影响的 PV 的回收策略更改为 Retain

要将 PV 的回收策略设置为 Retain,使用 kubectl patch pv: kubectl patch pv <pv-name> -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'

恢复意外删除的块 (Google Cloud 特定)

本手册假设您已在 GCS 存储桶中启用版本控制,并且已删除块的保留期尚未到期。

使用 undelete-block-gcs 工具恢复意外删除的块

步骤 1:编译 undelete-block-gcs 工具,其源代码可在 Mimir 仓库的 tools/undelete-block-gcs/ 路径下获取。

步骤 2:构建要恢复的 TSDB 块列表,并将其存储到名为 deleted-list 的文件中。文件应包含每行 1 个块的路径,以 gs:// 为前缀。例如:

gs://bucket/tenant-1/01H6NCQVS3D3H6D8WGBZ9KB41Z
gs://bucket/tenant-1/01H6NCR7HSZ8DHKEG9SSJ0QZKQ
gs://bucket/tenant-1/01H6NCRBJTY8R1F4FQJ3B1QK9W

步骤 3:运行 undelete-block-gcs 工具来恢复已删除的块

cat deleted-list | undelete-block-gcs -concurrency 16

注意

我们建议首先在一个块上尝试 undelete-block-gcs,确保它被正确恢复,然后针对更大的一组块运行以进行恢复。

使用 gsutil 恢复意外删除的块

这些只是示例操作,但应该能让您大致了解如何执行此操作。在继续之前,请阅读 GCS 文档

步骤 1:使用 gsutil ls -l -a $BUCKET 列出所有块,包括已删除的块。现在确定已删除的块,并将要恢复的块保存在名为 deleted-block-list 的文件中(每行一个块)。

  • -l 打印长列表
  • -a 在列表中包含非当前对象版本/生成。与 -l 选项结合使用时,还打印每个列出对象的元生成。

步骤 2:获得 deleted-block-list 后,现在可以列出需要恢复的所有对象,因为只能恢复对象而不能恢复前缀

while read block; do
# '-a' includes non-current object versions / generations in the listing
# '-r' requests a recursive listing.
gsutil ls -a -r $block | grep "#" | grep --invert-match deletion-mark.json
done < deleted-list > full-deleted-file-list

上述脚本将忽略不应恢复的 deletion-mark.jsonindex.cache.json

步骤 3:运行以下脚本恢复对象

while read file; do
gsutil cp $file ${file%#*}
done < full-deleted-file-list

调试 distroless 容器镜像 (在 Kubernetes 中)

Mimir 发布“distroless”容器镜像。distroless 镜像只包含运行单个二进制文件所需的极少内容。它们不包含任何文本编辑器、进程管理器、包管理器或其他调试工具,除非应用程序本身需要这些工具。

这在诊断问题时可能会带来挑战。容器内没有可连接的 shell,也没有工具来检查配置文件等。

但是,要调试 distroless 容器,我们可以采用将一个更完整的容器附加到现有容器的命名空间的方法。这使我们能够引入可能需要的所有工具,并且不干扰现有环境。也就是说,我们无需重启正在运行的容器即可附加我们的调试工具。

创建调试容器

Kubernetes 提供了一个命令,允许我们在预先存在的 pod 中启动一个临时的调试容器,并将其附加到与该 pod 中其他容器相同的命名空间。有关该命令以及如何调试正在运行的 pod 的更多详细信息,请参阅Kubernetes 文档

bash
kubectl --namespace mimir debug -it pod/compactor-0 --image=ubuntu:latest --target=compactor --container=mimir-debug-container
  • pod/name 是要附加的 pod。
  • --target= 是该 pod 中与之共享内核命名空间的容器。
  • --image= 是您希望使用的调试容器镜像。
  • --container 是临时容器的名称。这是可选的,但如果您想重复使用它,则非常有用。

您现在可以看到此空间中运行的所有进程。例如:

/ # ps aux
PID   USER     TIME  COMMAND
    1 root      5:36 /usr/bin/mimir -flags
   31 root      0:00 /bin/bash
   36 root      0:00 ps aux

PID 1 是在目标容器中执行的进程。您现在可以使用调试镜像中的工具与正在运行的进程进行交互。但是请注意,您的根路径和重要的环境变量(如 $PATH)将与目标容器不同。

目标容器的根文件系统可在 /proc/1/root 中找到。例如,/data 将位于 /proc/1/root/data,而目标容器的二进制文件将位于 /proc/1/root/usr/bin/mimir 之类的地方。

从 distroless 容器复制文件

由于 distroless 镜像中没有 tar,因此无法使用 kubectl cp 复制文件。

要解决此问题,您可以创建一个附加到 pod 的调试容器(如上所述),然后对该容器使用 kubectl cp。调试容器不能终止才能使用它。这意味着如果您运行调试容器以获得 shell,则需要保持 shell 打开才能执行以下操作。

例如,为 compactor-0 pod 创建了一个名为 mimir-debug-container 的调试容器后,运行以下命令将 compactor pod 中的 /etc/hostname 复制到本地机器上的 ./hostname

bash
kubectl --namespace mimir cp compactor-0:/proc/1/root/etc/hostname -c mimir-debug-container ./hostname
  • -c 是要在其中执行的调试容器。

但请注意,kubectl cp 存在一个限制,它无法跟随符号链接。为了解决这个问题,我们同样可以使用 exec 来创建一个 tar 包。

例如,您可以对您感兴趣的路径创建一个 tar 包,然后在本地提取它

bash
kubectl --namespace mimir exec compactor-0 -c mimir-debug-container -- tar cf - "/proc/1/root/etc/cortex" | tar xf -

请注意,您从中复制文件的容器必须仍然运行。如果您之前已经退出了调试容器,则该容器已停止,无法用于复制文件。在这种情况下,您需要启动一个新的容器。

清理和限制

使用临时容器(即 kubectl debug 的封装)的一个缺点是,它们被添加到 Pod 后就无法更改。这包括无法删除它们。如果调试容器中的进程已结束(例如,shell 已退出),则容器将保持在 Terminated 状态。这是无害的,并且将一直保留在那里,直到 Pod 被删除(例如,由于滚动更新)。

日志行

包含“具有重复时间戳但值不同”的样本的日志行

这意味着接收到的样本与最新的样本时间戳相同,但值不同。发生的次数记录在具有标签 reason="new-value-for-timestamp"cortex_discarded_samples_total 指标中。

可能的原因如下

  • 不正确的 relabeling 规则可能导致标签从序列中删除,从而使多个序列具有相同的标签。如果这些序列是从同一目标收集的,它们将具有相同的时间戳。
  • 刮取器在每次刮取时设置相同的时间戳。请注意,刮取器通常不应设置时间戳。