4.3 分层存储与保留策略 本节摘要:数据的存储成本应该跟着它的热度走。本节讲清分层存储如何把冷账本卸载到对象存储、卸载后读旧消息走什么路径;再把 Retention(数据保留)与 TTL(消费时限)两套过期规矩区分开,给不同命名空间配出合理的生命周期策略。 冷货去远洋:分层存储的经营逻辑 账本封存变只读之后,它大概率再也不会被写入,只是偶尔被某个慢订阅翻出来读。让这样的冷账本继续占着昂贵的 SSD,是货仓里最常见的浪费。分层存储的思路直接:把封存的账本卸载(offload)到对象存储,本地 Bookie 只留索引;有人要读时再从对象存储拉回来。对象存储的单位成本低一个数量级,长期保留的账本搬过去,热数据的盘就腾给了真正需要低延迟的写入。
本节摘要:数据的存储成本应该跟着它的热度走。本节讲清分层存储如何把冷账本卸载到对象存储、卸载后读旧消息走什么路径;再把 Retention(数据保留)与 TTL(消费时限)两套过期规矩区分开,给不同命名空间配出合理的生命周期策略。
账本封存变只读之后,它大概率再也不会被写入,只是偶尔被某个慢订阅翻出来读。让这样的冷账本继续占着昂贵的 SSD,是货仓里最常见的浪费。分层存储的思路直接:把封存的账本卸载(offload)到对象存储,本地 Bookie 只留索引;有人要读时再从对象存储拉回来。对象存储的单位成本低一个数量级,长期保留的账本搬过去,热数据的盘就腾给了真正需要低延迟的写入。
卸载由命名空间策略自动触发:设定"账本封存超过多久就卸载、卸到哪个后端",后续新封存的账本自动执行。两个必须理解的行为细节:其一,卸载是复制后删除——先把账本完整写到对象存储,校验通过才删本地副本,中途失败不损数据;其二,卸载的粒度是账本,不是消息,所以热账本(还在写的)永远留在本地,只有封存账本符合条件才走。

初学者最容易把这两个概念搅在一起,先立边界:
Retention(保留策略)作用于数据本身:消息无论有没有被消费,从写入时刻起保留多久(或多大),到期物理删除。它回答的是"账本里的字最多放多久"。
TTL(存活时限)作用于消费进度:消息超过一定时长没被任何订阅消费,就替所有订阅"补签收",此后按 Retention 的节奏清理。它回答的是"过期的未消费消息还要不要等"。
两者的组合语义用场景最好懂。审计流要求"数据必须留满合规期限",无论消费与否——Retention 设一年,TTL 关闭。遥测数据"三天没人读就没价值了"——TTL 设三天,Retention 设短一些配合清理。数仓补数订阅"三个月不追也不许删底账"——Retention 设三个月以上,且注意 TTL 一旦开启会让慢订阅被"补签收",补数就会漏数据。
配置命令按命名空间执行,看到差异了吗——两个旋钮完全独立:
# 保留:无消费也至少保留七天,且至少保留 10GB 上限内全留 $ pulsar-admin namespaces set-retention trade-order/transaction \ --time 7d --size 10G # TTL:未消费超过三天的消息视为消费完成(不再等待慢订阅) $ pulsar-admin namespaces set-message-ttl trade-order/transaction --ttl 3d # 验证当前策略 $ pulsar-admin namespaces get-retention trade-order/transaction $ pulsar-admin namespaces get-message-ttl trade-order/transaction
把本章三节串成一次真实复盘。现象:订单集群的 Bookie 磁盘水位以周为单位上涨,写入量却没涨。排查路径值得照着走一遍:
# 第一步:看磁盘水位到底涨在哪个主题的账本上 $ pulsar-admin topics stats-internal persistent://trade-order/transaction/order-events # 输出显示:封存账本数量持续增加,游标推进正常 # 第二步:查命名空间保留策略——发现曾为某次审计临时设过"保留一个月" $ pulsar-admin namespaces get-retention trade-order/transaction # 输出:retentionTimeInMinutes=43200(三十天) # 第三步:处置——审计期已过,保留回归七天,并开启分层把冷账本卸载 $ pulsar-admin namespaces set-retention trade-order/transaction --time 7d --size 10G $ pulsar-admin namespaces set-offload-policies trade-order/transaction \ --bucket pulsar-cold-storage --threshold 1G
复盘结论写进运维手册:磁盘水位的异常增长先查保留策略变更史,再查订阅积压——前者是数据"该走没走",后者是数据"有人没领"。两种病因对应两种药方,别上来就扩盘。
配置分层策略前,用一份核对清单把前置条件过一遍,能省掉大半返工。后端可达性:Bookie 节点到对象存储的网络连通与带宽预估——卸载流量会占用出网带宽,错峰配置要有依据。凭证与权限:对象存储的访问凭证按最小权限发放,只给目标桶的读写,凭证轮换流程先想好。卸载阈值:账本封存后等多久卸载(太短会频繁搬刚封存的账本,太长热盘浪费),与单账本大小阈值配合调。读取预算:冷读延迟变高后,谁在读冷数据——数仓批任务可接受,在线接口不可接受;把冷读路径告知所有下游。
配置完成后验证分三步:造一段超过卸载阈值的测试数据,等账本封存并触发卸载;从管理端确认账本位置已指向对象存储;再用 Reader 从最早坐标读旧消息,验证冷读路径通畅、延迟在预期内。三步走完,分层才算真正落地——策略配置成功不等于链路可用,验证永远是最后一公里。
给个能拍板的算法。设集群每天新写入两百吉字节,保留三十天,稳态数据量约六太字节。全留 SSD:按热盘单价乘六太字节,再乘副本份数。开分层、七天热保留:热盘只承担约一点四太字节(七天流量乘份数),其余四点六太字节进对象存储——对象存储单价通常低到热盘的零头,再叠加对象存储按三副本计费甚至纠删码更省的因素,稳态存储成本常能砍掉一大半。代价清单同样要写:冷读延迟上升、卸载带宽占用、组件链路变长带来的排障面扩大。把这张账算给业务方看,分层就不是运维的单方面决定,而是成本与延迟的联合决策——这也是本节作为存储章收尾最想传达的工作方式。
第 4 章收拢:货仓的地址学、算术与经营规矩都已清账。第 5 章回到甲板,亲手写代码操舵。