一、业务场景 & 目标
某电商风控链路每天高峰期 TPS 过百万。为了降低本地 SSD 成本、把恢复窗口(RTO)与历史回溯做长做稳,你希望:
- 热数据(最近几小时或几天)仍走 本地盘,低延迟、高吞吐;
- 冷数据(更久以前)自动转移到 远程对象存储(S3/HDFS/自研),按需回冷;
- Kafka 透明管理冷热数据,消费者无感,无需你写双写/搬迁脚本。
Kafka 的 Tiered Storage(分层存储)正为此而生:Broker 在后台把不再“热”的日志段复制到远程存储,同时保留必要的本地段;消费者读取旧数据时,Broker 会按需从远程拉回索引/数据,继续顺滑服务。
二、体系结构速览(概念到动作)
- RemoteStorageManager(RSM):真正跟远端存储打交道(上传、下载、删除远程段)。具体实现由插件提供。
- RemoteLogMetadataManager(RLMM):管理远程段的元数据(写到一个 元数据主题),Broker 通过它来定位远程段。
- Broker 端调度器:负责复制/清理/回冷等任务;还有用于读取远程段的线程池与索引缓存。
启用分层存储的最小动作就是:装好 RSM/RLMM 插件,开启功能开关,并给出必要的线程池与配额限制,避免后台任务“吃满带宽”。
三、从 0 到 1:一份可直接落地的 server.properties
样例
说明:不同存储厂商的 RSM/RLMM 实现类名与配置项略有差异,请替换为你所选插件包的类名与参数(文末给出“所有原生命名配置项的中文解读”,你可以逐一核对)。
############################
# 1) 开启分层存储(系统级)
############################
remote.log.storage.system.enable=true
############################
# 2) 远程存储实现(按你的插件替换)
############################
remote.log.storage.manager.class.name=your.rsm.impl.ClassName
remote.log.storage.manager.class.path=/opt/kafka/libs/rsm/* # 可选
remote.log.storage.manager.impl.prefix=rsm.config. # 固定前缀,用于传参
rsm.config.bucket=my-kafka-bucket # 例:S3/HDFS 等参数
rsm.config.region=ap-southeast-1
############################
# 3) 远程元数据管理(RLMM)
############################
remote.log.metadata.manager.class.name=org.apache.kafka.server.log.remote.metadata.storage.TopicBasedRemoteLogMetadataManager
remote.log.metadata.manager.class.path=/opt/kafka/libs/rlmm/* # 可选
remote.log.metadata.manager.impl.prefix=rlmm.config.
remote.log.metadata.manager.listener.name=PLAINTEXT # 或你的 listener
# RLMM 专用主题(容量/可靠性建议与集群规模相称)
remote.log.metadata.topic.num.partitions=50
remote.log.metadata.topic.replication.factor=3
remote.log.metadata.topic.retention.ms=-1
############################
# 4) 本地/远程保留与配额(吞吐/成本的“手刹”)
############################
# 本地保留(建议 <= 对应全局 log.retention.*)
log.local.retention.bytes=-2 # 继承 log.retention.bytes
log.local.retention.ms=-2 # 继承 log.retention.ms
# 上传/下拉总速率(全局限速,避免“拖库”)
remote.log.manager.copy.max.bytes.per.second=200000000 # ~200MB/s 按需调整
remote.log.manager.fetch.max.bytes.per.second=200000000 # ~200MB/s 按需调整
remote.log.manager.copy.quota.window.num=11
remote.log.manager.copy.quota.window.size.seconds=1
remote.log.manager.fetch.quota.window.num=11
remote.log.manager.fetch.quota.window.size.seconds=1
############################
# 5) 线程池与队列(别太小,也别放飞)
############################
remote.log.manager.copier.thread.pool.size=10
remote.log.manager.expiration.thread.pool.size=10
remote.log.manager.thread.pool.size=2
remote.log.reader.threads=10
remote.log.reader.max.pending.tasks=100
############################
# 6) 远程索引缓存(让“回冷”少走弯路)
############################
remote.log.index.file.cache.total.size.bytes=1073741824 # 1GiB,可按热点调大
############################
# 7) 超时与调度
############################
remote.fetch.max.wait.ms=500
remote.list.offsets.request.timeout.ms=30000
remote.log.manager.task.interval.ms=30000
# RLMM 初始化稳健性
remote.log.metadata.initialization.retry.interval.ms=100
remote.log.metadata.initialization.retry.max.timeout.ms=120000
remote.log.metadata.consume.wait.ms=120000
remote.log.metadata.custom.metadata.max.bytes=128
############################
# 8) 存储实现的安全与网络(如需)
############################
# 与 RSM/RLMM 插件的安全参数同前缀传入,例如:
# rsm.config.s3.access.key=...
# rsm.config.s3.secret.key=...
按主题启用:分层存储属于 Broker 功能,但是否把某个 topic 的段上传到远端通常由实现/策略决定(不同插件支持不同粒度的开关或按保留策略触发)。通用做法是:把热保留(本地)设短,把全局保留设长,让“超出本地阈值”的段进入远程层。
四、参数全解(逐项中文说明 + 经验提示)
下列条目完整覆盖相关配置,保留原始键名,便于你对照运维脚本与 CMDB。
1)本地保留
log.local.retention.bytes
:单分区在本地可保留的最大段大小之和。-2
继承log.retention.bytes
;实际必须 ≤log.retention.bytes
。
Type: long | Default: -2 | Importance: mediumlog.local.retention.ms
:单分区在本地可保留的时间。-2
继承log.retention.ms
;实际必须 ≤log.retention.ms
。
Type: long | Default: -2 | Importance: medium
经验:将本地保留设置为“热窗口”(例如 48 小时);全局保留继续按业务需要(例如 7~30 天)。这样超出热窗口的段就会迁往远程。
2)远程拉取/列举超时
remote.fetch.max.wait.ms
:服务端响应远程 fetch 前的最大等待。
int | 500 | [1, …] | mediumremote.list.offsets.request.timeout.ms
:服务端等待“远程 list offsets”完成的最大时间。
long | 30000 | [1, …] | medium
3)复制/清理/拉取配额与线程池
- 复制线程池:
remote.log.manager.copier.thread.pool.size
(int | 10) - 复制速率:
remote.log.manager.copy.max.bytes.per.second
(long | Long.MAX_VALUE) - 复制配额窗口:
remote.log.manager.copy.quota.window.num
(int | 11),
remote.log.manager.copy.quota.window.size.seconds
(int | 1) - 清理线程池:
remote.log.manager.expiration.thread.pool.size
(int | 10) - 拉取速率:
remote.log.manager.fetch.max.bytes.per.second
(long | Long.MAX_VALUE) - 拉取配额窗口:
remote.log.manager.fetch.quota.window.num
(int | 11),
remote.log.manager.fetch.quota.window.size.seconds
(int | 1) - Follower 远程 offset 读取线程:
remote.log.manager.thread.pool.size
(int | 2)
经验:
- 先设配额再扩线程。配额是“总阀门”,线程是“并发度”,二者配合才能既不拖库也不积压。
- 峰值期不要把复制/回冷速率开太大,否则与线上生产流量抢资源。
4)远程读取与索引缓存
- 远程读取线程池大小:
remote.log.reader.threads
(int | 10) - 读取任务队列上限:
remote.log.reader.max.pending.tasks
(int | 100;满则 fetch 报错) - 索引文件本地缓存:
remote.log.index.file.cache.total.size.bytes
(long | 1GiB)
经验:索引缓存是“命中率关键”,回放/回查越多,越应该把它适度调大。
5)RSM:远程存储管理器(必须配置)
- 实现类名:
remote.log.storage.manager.class.name
(string | 必填) - 实现类路径:
remote.log.storage.manager.class.path
(string | 可选) - 实现参数前缀:
remote.log.storage.manager.impl.prefix
(string |rsm.config.
) - 系统总开关:
remote.log.storage.system.enable
(boolean | false)
经验:把所有 RSM 相关安全凭据(AK/SK、endpoint、region…)都用
rsm.config.*
前缀按需注入,便于隔离与审计。
6)RLMM:远程元数据管理(强烈建议使用 TopicBased 实现)
- 实现类名:
remote.log.metadata.manager.class.name
(默认:TopicBased 实现) - 实现类路径:
remote.log.metadata.manager.class.path
(可选) - 实现参数前缀:
remote.log.metadata.manager.impl.prefix
(默认:rlmm.config.
) - 连接本地 broker 的 listener 名:
remote.log.metadata.manager.listener.name
(如需) - 消费/发布等待与初始化重试:
remote.log.metadata.consume.wait.ms
(long | 120000)、
remote.log.metadata.initialization.retry.interval.ms
(long | 100)、
remote.log.metadata.initialization.retry.max.timeout.ms
(long | 120000) - 自定义元数据大小上限:
remote.log.metadata.custom.metadata.max.bytes
(int | 128) - RLMM 主题:
remote.log.metadata.topic.num.partitions
(int | 50)、
remote.log.metadata.topic.replication.factor
(short | 3)、
remote.log.metadata.topic.retention.ms
(long | -1)
经验:RLMM 主题是“远程段目录”,不要过早清理;分区数与副本因子按集群规模与高可用要求设置。
7)后台任务调度
- 周期:
remote.log.manager.task.interval.ms
(long | 30000)
五、容量与性能:怎么“算一笔账”
- 本地盘估算:
本地保留时长(小时) × 峰值生产速率(MB/s) × 3600 × 分区数 × 副本因子
👉 得到热层最低磁盘需求;再按 1.3~1.5 倍预留。 - 远程带宽阀值:
起步建议把copy.max.bytes.per.second
、fetch.max.bytes.per.second
设为集群带宽的 10%~30%,观察后再放开。 - 索引缓存:
有回放/补数/审计需求时,把remote.log.index.file.cache.total.size.bytes
调到 2~4 GiB 起步更稳。
六、运维排障清单(常见坑)
远程类加载失败
- 现象:Broker 启动报类找不到。
- 排查:
remote.log.storage.manager.class.name/class.path
、…metadata.manager…class.path
是否正确;插件依赖是否齐全。
队列打满
- 现象:
remote.log.reader.max.pending.tasks
满载,Fetch 报错。 - 处理:增大该值或增加
remote.log.reader.threads
;更关键是限速,别让后台拉取和线上抢 IO。
- 现象:
复制拖垮集群
- 现象:生产延迟飙升。
- 处理:立即下调
copy.max.bytes.per.second
;必要时减少…copier.thread.pool.size
。
本地热层“被清空”
- 现象:热点数据也频繁走远程。
- 排查:是否把
log.local.retention.*
设得太小;或log.retention.*
与 topic 级策略冲突。
元数据初始化失败
- 现象:Broker 启动后自杀(超过
remote.log.metadata.initialization.retry.max.timeout.ms
)。 - 处理:检查 RLMM 主题权限、监听器可达性、集群健康。
- 现象:Broker 启动后自杀(超过
七、上线步骤建议(灰度方案)
- 装插件(RSM/RLMM)→ 单 Broker 验证类加载;
- 开功能(
remote.log.storage.system.enable=true
),设置配额与线程池为保守值; - 挑选 1~2 个 Topic 灰度:缩短本地保留(例如 24~48h);
- 观察:复制速率、远程读写错误、消费者延迟、索引缓存命中;
- 逐步扩大 Topic 范围与配额,形成稳定巡检与告警规则。
附:3.10 Tiered Storage 全参数索引(便于检索)
- 本地保留:
log.local.retention.bytes
/log.local.retention.ms
- 远程 fetch/list offsets 超时:
remote.fetch.max.wait.ms
/remote.list.offsets.request.timeout.ms
- 复制:
remote.log.manager.copier.thread.pool.size
/remote.log.manager.copy.max.bytes.per.second
/remote.log.manager.copy.quota.window.num
/remote.log.manager.copy.quota.window.size.seconds
- 清理:
remote.log.manager.expiration.thread.pool.size
- 拉取:
remote.log.manager.fetch.max.bytes.per.second
/remote.log.manager.fetch.quota.window.num
/remote.log.manager.fetch.quota.window.size.seconds
- Follower 远程 offset 读取:
remote.log.manager.thread.pool.size
- 远程读取线程 & 队列:
remote.log.reader.threads
/remote.log.reader.max.pending.tasks
- 索引缓存:
remote.log.index.file.cache.total.size.bytes
- RSM:
remote.log.storage.manager.class.name
/remote.log.storage.manager.class.path
/remote.log.storage.manager.impl.prefix
/remote.log.storage.system.enable
- RLMM:
remote.log.metadata.manager.class.name
/remote.log.metadata.manager.class.path
/remote.log.metadata.manager.impl.prefix
/remote.log.metadata.manager.listener.name
/
remote.log.metadata.custom.metadata.max.bytes
/remote.log.metadata.consume.wait.ms
/
remote.log.metadata.initialization.retry.interval.ms
/remote.log.metadata.initialization.retry.max.timeout.ms
/
remote.log.metadata.topic.num.partitions
/remote.log.metadata.topic.replication.factor
/remote.log.metadata.topic.retention.ms
- 调度周期:
remote.log.manager.task.interval.ms