Kafka 分层存储(Tiered Storage)从 0 到 1 的配置、调优与避坑

一、业务场景 & 目标

某电商风控链路每天高峰期 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 实现类名与配置项略有差异,请替换为你所选插件包的类名与参数(文末给出"所有原生命名配置项的中文解读",你可以逐一核对)。

properties 复制代码
############################
# 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: medium
  • log.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, ...] | medium
  • remote.list.offsets.request.timeout.ms :服务端等待"远程 list offsets"完成的最大时间
    long | 30000 | [1, ...] | medium

3)复制/清理/拉取配额与线程池

  • 复制线程池remote.log.manager.copier.thread.pool.sizeint | 10
  • 复制速率remote.log.manager.copy.max.bytes.per.secondlong | Long.MAX_VALUE
  • 复制配额窗口
    remote.log.manager.copy.quota.window.numint | 11 ),
    remote.log.manager.copy.quota.window.size.secondsint | 1
  • 清理线程池remote.log.manager.expiration.thread.pool.sizeint | 10
  • 拉取速率remote.log.manager.fetch.max.bytes.per.secondlong | Long.MAX_VALUE
  • 拉取配额窗口
    remote.log.manager.fetch.quota.window.numint | 11 ),
    remote.log.manager.fetch.quota.window.size.secondsint | 1
  • Follower 远程 offset 读取线程remote.log.manager.thread.pool.sizeint | 2

经验

  • 先设配额再扩线程。配额是"总阀门",线程是"并发度",二者配合才能既不拖库也不积压。
  • 峰值期不要把复制/回冷速率开太大,否则与线上生产流量抢资源。

4)远程读取与索引缓存

  • 远程读取线程池大小remote.log.reader.threadsint | 10
  • 读取任务队列上限remote.log.reader.max.pending.tasksint | 100;满则 fetch 报错)
  • 索引文件本地缓存remote.log.index.file.cache.total.size.byteslong | 1GiB

经验 :索引缓存是"命中率关键",回放/回查越多,越应该把它适度调大

5)RSM:远程存储管理器(必须配置)

  • 实现类名remote.log.storage.manager.class.namestring | 必填
  • 实现类路径remote.log.storage.manager.class.pathstring | 可选
  • 实现参数前缀remote.log.storage.manager.impl.prefixstring | rsm.config.
  • 系统总开关remote.log.storage.system.enableboolean | 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.mslong | 120000 )、
    remote.log.metadata.initialization.retry.interval.mslong | 100 )、
    remote.log.metadata.initialization.retry.max.timeout.mslong | 120000
  • 自定义元数据大小上限remote.log.metadata.custom.metadata.max.bytesint | 128
  • RLMM 主题
    remote.log.metadata.topic.num.partitionsint | 50 )、
    remote.log.metadata.topic.replication.factorshort | 3 )、
    remote.log.metadata.topic.retention.mslong | -1

经验 :RLMM 主题是"远程段目录",不要过早清理;分区数与副本因子按集群规模与高可用要求设置。

7)后台任务调度

  • 周期remote.log.manager.task.interval.mslong | 30000

五、容量与性能:怎么"算一笔账"

  • 本地盘估算
    本地保留时长(小时) × 峰值生产速率(MB/s) × 3600 × 分区数 × 副本因子
    👉 得到热层最低磁盘需求;再按 1.3~1.5 倍预留。
  • 远程带宽阀值
    起步建议把 copy.max.bytes.per.secondfetch.max.bytes.per.second 设为集群带宽的 10%~30%,观察后再放开。
  • 索引缓存
    有回放/补数/审计需求时,把 remote.log.index.file.cache.total.size.bytes 调到 2~4 GiB 起步更稳。

六、运维排障清单(常见坑)

  1. 远程类加载失败

    • 现象:Broker 启动报类找不到。
    • 排查:remote.log.storage.manager.class.name/class.path...metadata.manager...class.path 是否正确;插件依赖是否齐全。
  2. 队列打满

    • 现象:remote.log.reader.max.pending.tasks 满载,Fetch 报错。
    • 处理:增大该值或增加 remote.log.reader.threads;更关键是限速,别让后台拉取和线上抢 IO。
  3. 复制拖垮集群

    • 现象:生产延迟飙升。
    • 处理:立即下调 copy.max.bytes.per.second;必要时减少 ...copier.thread.pool.size
  4. 本地热层"被清空"

    • 现象:热点数据也频繁走远程。
    • 排查:是否把 log.local.retention.* 设得太小;或 log.retention.* 与 topic 级策略冲突。
  5. 元数据初始化失败

    • 现象:Broker 启动后自杀(超过 remote.log.metadata.initialization.retry.max.timeout.ms)。
    • 处理:检查 RLMM 主题权限、监听器可达性、集群健康。

七、上线步骤建议(灰度方案)

  1. 装插件(RSM/RLMM)→ 单 Broker 验证类加载;
  2. 开功能remote.log.storage.system.enable=true),设置配额与线程池保守值
  3. 挑选 1~2 个 Topic 灰度:缩短本地保留(例如 24~48h);
  4. 观察:复制速率、远程读写错误、消费者延迟、索引缓存命中;
  5. 逐步扩大 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
  • RSMremote.log.storage.manager.class.name / remote.log.storage.manager.class.path / remote.log.storage.manager.impl.prefix / remote.log.storage.system.enable
  • RLMMremote.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
相关推荐
bjzw3 小时前
Kafka常见问题及解决方案
分布式·kafka
小白学大数据5 小时前
分布式爬虫的全局请求间隔协调与IP轮换策略
分布式·爬虫·tcp/ip
半桶水专家5 小时前
Kafka 架构详解
分布式·架构·kafka
shinelord明5 小时前
【大数据技术实战】Flink+DS+Dinky 自动化构建数仓平台
大数据·运维·分布式·架构·flink·自动化
潘达斯奈基~5 小时前
kafka:【1】概念关系梳理
分布式·kafka
云雾J视界8 小时前
百万级并发下的微服务架构设计之道:从阿里双11看分布式系统核心原则与落地实践
分布式·微服务·云原生·架构
灵犀学长8 小时前
Spring Boot集成Kafka常见业务场景最佳实践实战指南
java·spring boot·后端·kafka
缘来如此098 小时前
Kafka&RocketMQ重平衡容灾机制
分布式·kafka·rocketmq
一叶飘零_sweeeet9 小时前
从 0 到 1 吃透 Nacos:服务发现与配置中心的终极实践指南
java·分布式·服务发现