Prometheus TSDB WAL 重放缺陷:序列删除后的数据丢失

概述

在 Prometheus 的时间序列数据库(TSDB)中,Write-Ahead Log(WAL)和 Write-Behind Log(WBL)是保证数据持久性和在重启或崩溃后恢复数据的关键组件。WAL 重放过程负责将日志中记录的样本重新加载到内存中。本文档解析了一个在 WAL 重放过程中出现的竞态条件缺陷,该缺陷会导致特定条件下序列的所有样本数据在重启后丢失,并详细阐述了修复方案。

核心概念

要理解此问题,需要先明确以下几个关键概念:

  • WAL (Write-Ahead Log):所有写入 TSDB 的数据(包括样本、删除标记等)首先记录到 WAL 中,然后再应用到内存中的 Head 块。这保证了数据在进程崩溃后仍能恢复。
  • WBL (Write-Behind Log):在 Head 块压缩(Compaction)过程中产生,记录了压缩期间新接收的样本,以确保数据完整性。
  • 序列 (Series):由一组唯一的标签定义的时间序列。每个序列在 TSDB 中有一个唯一的内部引用(ref)。
  • Stale Deletion (陈旧删除):当一个序列在指定时间内没有新样本时,会被标记为陈旧并最终删除。这是一种异步且分片执行的操作。
  • 序列重建 (Series Re-creation):在一个序列被陈旧删除后,很快又收到具有相同标签的写入,从而创建一个新的序列对象(可能带有新的 ref)。

实践

问题分析:竞态条件如何发生

该问题源于 WAL 重放过程中两个关键操作的并行执行与不同步:

  1. 异步删除:序列的陈旧删除(由“完整删除墓碑”触发)被分片并异步地应用于重放处理器。
  2. 同步解析:新的序列记录(代表同一标签的序列重建)在主分发协程中被解析并映射到序列对象。

竞态条件发生于以下时序:

  1. WAL 中存在一条“完整删除墓碑”记录,用于删除序列 A。
  2. 紧随其后,WAL 中出现一条记录,用于创建具有相同标签的新序列 B(序列重建)。
  3. 在主分发协程处理这条新记录时,删除操作尚未被对应的处理器应用。因此,该记录解析出的新 ref 被错误地映射到了“注定死亡”的旧序列对象 A 上。
  4. 随后,删除操作被处理器应用,序列对象 A 被标记为已删除。
  5. 重放继续进行,所有属于新 ref(本应属于新序列 B)的样本记录,都会因为引用了一个已被删除的序列对象而被丢弃,导致新序列的所有数据丢失。

修复方案:追踪与替换

修复的核心思路是在分发协程中主动追踪那些已发出删除指令但尚未被处理器应用的序列对象。

  1. 追踪待删除对象:当分发协程发出删除指令时,会在一个映射表中记录该序列对象及其 ref。
  2. 拦截与替换:在重放序列记录时,如果发现新解析的 ref 映射到了一个正在被追踪的“待删除”对象,则执行以下操作:
    • 解除映射:将该序列对象从查找映射中移除(通过指针标识确保安全,防止与正在应用删除的处理器冲突)。
    • 重建序列:为新的记录创建一个全新的序列对象,并使用其自身的 ref 进行映射。
  3. 会计处理:被替换掉的旧序列对象,其统计信息(如样本计数等)将在其原始处理器上异步结算,且在所有进行中的追加操作完成之后进行。
  4. 损失统计:被替换掉的旧序列上仍排队等待处理的样本将被丢弃并计入“未知引用”计数器,而非被追加后再删除。这虽然导致 head_samples_re-appended_total 和 head_samples_deleted_total 指标不变,但会使 unknown_refs 计数器在触发此竞态条件的重放中升高。

最终,此修复确保了在陈旧删除后立即重建的序列能够正确接收其所有样本数据,结果状态与未发生竞态时完全一致。

SRE 要点

与可靠性的关联

此缺陷是一个严重的数据可靠性问题。在特定的时序条件下(高序列淘汰率伴随同标签的快速重写),Prometheus 重启后可能导致特定时间序列的数据永久性丢失,直接违反了数据持久性的承诺。

可观测性与事件响应

  • 可观测性:修复后,如果发生此类竞态,unknown_refs_total 计数器会出现非预期的峰值。SRE 可以通过监控此指标来识别是否发生过该竞态,尽管最终数据是完整的。这是一个重要的诊断线索。
  • 事件响应:如果监控发现 unknown_refs 在启动后异常增高,且伴有特定序列数据缺失的告警,应考虑是否与此竞态相关。需要检查 Prometheus 版本,并确认是否已应用此补丁。

最佳实践与反模式

  • 最佳实践:保持 Prometheus 版本更新,及时应用重要的 bug 修复补丁。对于关键监控系统,应在测试环境中验证升级。
  • 常见反模式:忽略启动日志中的 unknown_refs 警告。这些警告可能不仅仅表示简单的配置问题,也可能隐藏着更深层次的数据一致性竞态。

相关指标 (SLI/SLO/SLA)

  • SLI:此缺陷直接影响 数据持久性 与 数据准确性 的 SLI。修复后,应确保在相同负载和重启场景下,序列数据的丢失率为零。
  • SLO/SLA:数据丢失直接威胁到基于数据完整性的 SLO(例如“关键指标的数据保留期为15天”)。SRE 需要确保监控基础设施所依赖的 SLO 不会因此类底层存储缺陷而受损。可以将 unknown_refs_total 作为观测性指标纳入健康度评估。

相关页面:prometheus, tsdb, slo