Apache BookKeeper 是 Pulsar 的持久化存储层,负责高吞吐、低延迟、高可用地存储消息数据。理解 BookKeeper 的核心概念 —— Ledger(账本)的生命周期,是深入掌握 Pulsar 存储机制的关键。
📘 Pulsar 深入理解 BookKeeper:Ledger 生命周期详解
一、什么是 Ledger?
在 BookKeeper 中,Ledger(账本) 是一个 只追加(append-only)的日志单元,用于存储一组连续的消息。它是数据写入和复制的基本单位。
✅ 类比:
- Ledger ≈ Kafka 的 Log Segment
- Bookie ≈ 存储节点(类似 DataNode)
每个 Pulsar Topic 的消息会被写入一个或多个 Ledger,当当前 Ledger 达到大小或时间阈值时,会自动关闭并创建新 Ledger。
二、Ledger 的核心特性
| 特性 | 说明 |
|---|---|
| ✅ 只追加(Append-Only) | 一旦创建,只能写入,不能修改或删除(直到关闭) |
| ✅ 多副本(Ensemble) | 每条写入由多个 Bookie 副本确认 |
| ✅ 高可用 | 单个 Bookie 宕机不影响读写 |
| ✅ 独立生命周期 | 可单独关闭、删除 |
| ✅ 元数据存储在 ZooKeeper | 包括 Ledger ID、副本位置、状态等 |
三、Ledger 的生命周期(4 个阶段)
[ CREATE ] → [ WRITE ] → [ CLOSE ] → [ DELETE ]
阶段 1:CREATE(创建)
触发时机:
- Pulsar Broker 首次向某个 Topic 发送消息。
- 当前 Ledger 达到配置的 最大大小 或 最大生命周期。
创建过程:
- Broker 向 ZooKeeper 请求创建新 Ledger。
- ZooKeeper 分配唯一 Ledger ID。
- Broker 选择一个 Ensemble(一组 Bookie,如 3 个)作为写入副本。
- Ledger 元数据写入 ZooKeeper,状态为
OPEN。
相关配置(broker.conf):
# Ledger 最大大小(默认 512MB)
managedLedgerMaxLedgerSizeMB=512
# Ledger 最大生命周期(默认 6 小时)
managedLedgerMaxMarkDeleteLedgerAgeIntervalInMinutes=360
✅ 每个 Ledger 通常对应一个 BookKeeper 中的物理日志文件。
阶段 2:WRITE(写入)
写入流程:
- Producer 发送消息 → Pulsar Broker。
- Broker 将消息封装为 Entry(条目),写入当前打开的 Ledger。
- Broker 并行写入多个 Bookie(Ensemble)。
- 当达到 Ack Quorum(如 2/3)确认后,返回 ACK 给 Producer。
Broker → Bookie-1
→ Bookie-2 ← ACK
→ Bookie-3 ← ACK (quorum 满足)
关键概念:
| 术语 | 说明 |
|---|---|
| Ensemble Size | 参与写入的 Bookie 数量(如 3) |
| Write Quorum Size | 每次写入必须等待的副本数(如 3) |
| Ack Quorum Size | 返回 ACK 所需的最小确认数(如 2) |
✅ 配置示例:
ensemble=3, writeQuorum=3, ackQuorum=2→ 性能与可用性平衡。
写入性能优化:
- 批量写入:多个 Entry 打包发送。
- 异步写入:Broker 不等待所有副本完成。
- 缓存:Bookie 使用 Journal + Entry Log 提升写入速度。
阶段 3:CLOSE(关闭)
触发时机:
- Ledger 大小 ≥
managedLedgerMaxLedgerSizeMB - Ledger 年龄 ≥
managedLedgerMaxMarkDeleteLedgerAgeIntervalInMinutes - Broker 主动触发滚动(如负载均衡)
- 集群重启后自动恢复
关闭过程:
- Broker 停止向该 Ledger 写入新消息。
- 向所有 Bookie 发送 Close 请求。
- Bookie 确认关闭,更新状态为
CLOSED。 - Ledger 元数据在 ZooKeeper 中标记为不可写。
- 创建新 Ledger 接替写入。
✅ 关闭后,该 Ledger 仍可读取,但不能再写入。
为什么需要关闭?
- 防止单个 Ledger 过大,影响恢复速度。
- 便于垃圾回收(GC)清理已消费的数据。
阶段 4:DELETE(删除)
触发时机:
- Ledger 中的所有消息都已被所有订阅消费(游标已前进)
- 且消息保留策略(Retention)允许删除
- Ledger Offload(可选)完成后
删除过程:
- Pulsar Broker 的 ManagedLedger 检查哪些 Ledger 已“过期”。
- 调用 BookKeeper API 删除 Ledger。
- Bookie 物理删除数据文件(异步)。
- ZooKeeper 中的 Ledger 元数据被清除。
相关配置:
# 是否启用自动删除(默认 true)
managedLedgerCursorAutoSkipMode=disabled
# 消息保留策略(Namespace 级)
pulsar-admin namespaces set-retention my-tenant/my-namespace --time 72h --size 10G
⚠️ 删除是不可逆的,必须确保没有订阅需要重放。
四、Ledger 与 Pulsar Topic 的关系
Pulsar Topic
├── Partition-0
│ ├── Ledger-1 → [Entry-1, Entry-2, ...] → Closed → 可删除
│ ├── Ledger-2 → [Entry-3, Entry-4, ...] → Closed
│ └── Ledger-3 → [Entry-5, ...] → Open(正在写入)
├── Partition-1
│ └── Ledger-4 → Open
- 每个 Partitioned Topic 的分区 维护自己的 Ledger 序列。
- Ledger 滚动(Roll)是 Pulsar 实现 高吞吐、可扩展存储 的关键。
五、Ledger 的元数据存储(ZooKeeper)
每个 Ledger 的元数据存储在 ZooKeeper 中,路径示例:
/ledgers/L/00/00/01/meta
元数据内容包括:
- Ledger ID
- Ensemble 配置(Bookie 列表)
- 当前写入位置(Last Entry ID)
- 状态(OPEN/CLOSED)
- 密码(用于安全写入)
✅ ZooKeeper 不存储消息内容,只存元数据,性能压力小。
六、Ledger 的高可用与容错
| 故障场景 | 处理机制 |
|---|---|
| 单个 Bookie 宕机 | 写入继续,只要满足 ackQuorum |
| Bookie 永久故障 | 数据不丢失,其他副本仍可用;可启用 Autorecovery 自动修复 |
| Ledger 未关闭崩溃 | Broker 恢复时通过 Truncation 修复不一致 |
| ZooKeeper 故障 | 影响新 Ledger 创建,已有 Ledger 读写不受影响 |
✅ BookKeeper 支持 Autorecovery:自动将丢失副本的数据复制到新 Bookie。
七、Ledger 的监控与运维
常用 pulsar-admin 命令
# 查看 Topic 的 Ledger 信息
pulsar-admin topics stats persistent://my-tenant/my-namespace/my-topic
# 输出示例:
{
"ledgerDetails": {
"currentLedgerId": 123,
"lastLedgerCreatedTimestamp": "2024-01-01T12:00:00Z",
"ledgers": [
{ "ledgerId": 121, "state": "CLOSED", "size": 536870912 },
{ "ledgerId": 122, "state": "CLOSED", "size": 536870912 },
{ "ledgerId": 123, "state": "OPEN", "size": 234567890 }
]
}
}
# 强制滚动 Ledger(手动触发)
pulsar-admin topics trigger-managed-ledger-rollover persistent://my-tenant/my-namespace/my-topic
八、最佳实践建议
| 实践 | 建议 |
|---|---|
| ✅ 合理设置 Ledger 大小 | 太小:频繁滚动;太大:GC 压力大(推荐 512MB ~ 1GB) |
| ✅ 监控 Ledger 数量 | 过多 Ledger 可能影响 ZooKeeper 性能 |
| ✅ 启用 Retention 策略 | 防止磁盘打满 |
| ✅ 定期检查 Bookie 磁盘使用 | 避免写满 |
| ✅ 启用 Autorecovery | 提升可用性 |
| ✅ 备份 ZooKeeper 数据 | 防止元数据丢失 |
✅ 总结
| 阶段 | 关键动作 | 说明 |
|---|---|---|
| CREATE | 分配 ID,选择 Ensemble | Ledger 开始 |
| WRITE | 追加 Entry,多副本确认 | 高吞吐写入 |
| CLOSE | 停止写入,标记 CLOSED | 滚动到新 Ledger |
| DELETE | 清理已消费数据 | 释放存储空间 |
📌 一句话总结:
Ledger 是 Pulsar 消息的“存储单元” —— 它通过“创建 → 写入 → 关闭 → 删除”的生命周期,实现了高可用、可扩展、持久化的消息存储,是 Pulsar 分层架构的基石。
1836

被折叠的 条评论
为什么被折叠?



