我至今还记得团队第一次把内部消息系统容器化的场景:Kafka 容器明明已经起来了,日志也没报错,但客户端就是连不上 broker。后来查了一整天,问题出在 Kafka 的 listener 机制——它和 MySQL、Redis 那种"端口开好就能连"的中间件完全不同,容器里监听地址和对外广播地址一旦对不上,就会出现这种诡异的"假活"状态。
这篇文章就按我自己踩通的路子来写,从单机版的详细安装步骤讲起,一直讲到生产环境的三节点集群搭建,再到那些官方文档不会写的坑。不管你是第一次接触 Kafka 的新手,还是准备把现有 Kafka 迁到 Docker 里的老手,这篇实践指南应该都能帮你少走几趟弯路。
1. 先搞清楚 Kafka 在 Docker 里的架构,再动手不迟
1.1 Kafka 从不是"一个容器"能搞定的事
很多人第一次部署 Kafka 时,第一反应是找一个现成镜像docker run一把梭。这种做法理论上能跑起来,但实际使用中会立刻碰壁。根本原因在于:Kafka 不是一个独立进程,而是一套需要互相配合的组件体系。
一个最简 Kafka 环境至少包含这几个角色:broker(承担消息存储和读写)、元数据服务(负责管理主题、分区、副本的分配)以及客户端(生产者和消费者)。如果你用的是传统架构,元数据服务由 ZooKeeper 承担;如果用新架构,这个能力被内置到了 Kafka 进程本身。
主题(topic)是消息的分类单位,主题又分成多个分区(partition),分区是并行读写的物理单元。副本(replica)负责冗余,保证某个 broker 挂掉时数据不丢。消费者组(consumer group)则是横向扩展消费能力的方式。
这套概念如果你心里没底,后面验证集群、排查故障时会非常吃力。因为很多 Kafka 的安装问题根本不是"起不来",而是"起来了但各个组件之间互相不认识"。
1.2 ZooKeeper 模式与 KRaft 模式:新老两套架构怎么选
Kafka 2.8 开始引入了 KRaft 模式,把元数据管理从 ZooKeeper 挪回 Kafka 自身;3.3 版本之后 KRaft 正式 GA 可用。到了我现在常部署的 3.6、3.7 版本,KRaft 已经是官方推荐的主路径。
我给你的建议很直接:
- 新项目、个人学习、没有历史包袱的,直接用 KRaft。少维护一个 ZooKeeper 组件,启动和运维都简单很多。
- 公司里已有 ZooKeeper 运维体系、监控脚本、管理工具的,用 ZooKeeper 模式也不算错。它非常稳定,生态成熟,出问题容易找到参考资料。
- 不要混用。同集群里既有 KRaft 节点又有 ZooKeeper 节点是灾难,部署前先把模式定死。
两种模式对比大概是这样:
| 对比项 | ZooKeeper 模式 | KRaft 模式 |
|---|---|---|
| 元数据存储 | 由独立 ZooKeeper 集群管理 | 内置到 Kafka 控制器节点 |
| 组件数量 | Kafka + ZooKeeper | 仅 Kafka |
| 成熟度 | 极成熟,久经考验 | 3.3 后 GA,主流推荐 |
| 部署复杂度 | 多一套系统要维护 | 更简单 |
| 适用场景 | 存量系统、传统运维体系 | 新项目、容器化部署 |
1.3 镜像选型:别再用网上那些老掉牙的教程镜像了
镜像选择上,我见过太多人踩坑了。老教程里大量使用的wurstmeister/kafka镜像已经停止维护很久,里面组件版本陈旧,Kafka 升级、安全修复全都跟不上,新项目我强烈不推荐。
目前比较靠谱的镜像有这几个:
| 镜像 | 配置方式 | 适用场景 | 维护状态 |
|---|---|---|---|
| bitnami/kafka | 环境变量前缀KAFKA_CFG_,封装度高 | 新手入门、快速部署 | 活跃维护 |
| apache/kafka | 官方镜像,配置对应原生 properties | 熟悉 Kafka 原生配置的团队 | 活跃维护 |
| confluentinc/cp-kafka | 环境变量,附带完整生态工具 | 需要 Confluent 生态的团队 | 活跃维护 |
我自己的习惯是:快速做实验用bitnami/kafka,它对配置做了很好的封装,环境变量名好记,默认值合理;生产环境如果用 KRaft,我也倾向 bitnami,因为它会自动处理存储目录的格式化,省去手动初始化的步骤。后面涉及完整配置文件的场景,我会给出一个完整可用的 docker-compose 例子。
2. 从零启动单机版:先把链路跑通再说
2.1 环境准备:版本和端口检查
动手之前,先确认你的 Docker 环境没问题。Kafka 镜像普遍要求 Docker Engine 20.10 以上,Docker Compose 建议用 v2 版本。
docker --version docker compose version然后检查端口。默认情况下 Kafka 客户端连接走 9092,ZooKeeper 走 2181(如果用得到)。先确认这两个端口没被占用:
ss -lnt | grep -E '9092|2181'如果输出为空,说明端口是干净的。如果已经有进程监听,要么换端口,要么把旧进程处理掉。这一步别偷懒,很多"启动失败"其实都是端口冲突。
2.2 ZooKeeper 模式:两个容器的标准启动
先创建一个专用网络,让容器之间可以通过容器名互相访问:
docker network create kafka-network启动 ZooKeeper:
docker run -d --name zookeeper \ --network kafka-network \ -p 2181:2181 \ -e ALLOW_ANONYMOUS_LOGIN=yes \ bitnami/zookeeper:latest注意:
ALLOW_ANONYMOUS_LOGIN=yes表示允许匿名登录,只有本地测试时才建议这样用。生产环境必须配置认证,后面我会在安全相关段落里单独说明。
接着启动 Kafka,这里有几个环境变量是整个配置的核心:
docker run -d --name kafka \ --network kafka-network \ -p 9092:9092 \ -e KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181 \ -e KAFKA_CFG_LISTENERS=PLAINTEXT://:9092 \ -e KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092 \ -e ALLOW_PLAINTEXT_LISTENER=yes \ bitnami/kafka:latest解释一下这几个关键配置:
KAFKA_CFG_ZOOKEEPER_CONNECT:告诉 broker 去哪里找元数据服务,这里填的是 ZooKeeper 容器名加端口,因为它们在同一个自定义网络里。KAFKA_CFG_LISTENERS:broker 实际监听网卡和端口的位置。KAFKA_CFG_ADVERTISED_LISTENERS:broker 对外广播的地址。这是 Kafka 最容易出问题的地方,后面专门开一节讲。
2.3 验证 Kafka 是否真的能用
容器起来不等于 Kafka 能收发消息,必须亲手创建主题并跑一遍生产者消费者链路。
docker exec -it kafka bash进入容器后,切到 bin 目录:
cd /opt/bitnami/kafka/bin创建一个测试主题:
kafka-topics.sh --bootstrap-server localhost:9092 \ --create --topic quickstart \ --partitions 1 --replication-factor 1查看主题列表确认创建成功:
kafka-topics.sh --bootstrap-server localhost:9092 --list再开一个终端,启动生产者输入几条消息:
docker exec -it kafka bash cd /opt/bitnami/kafka/bin kafka-console-producer.sh --bootstrap-server localhost:9092 --topic quickstart输入几行文本,然后在新终端启动消费者:
docker exec -it kafka bash cd /opt/bitnami/kafka/bin kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic quickstart --from-beginning如果你能看到刚才输入的内容原样输出,说明单机链路的安装和配置已经完全跑通了。这也是我每次装完 Kafka 之后必做的基本检查。
2.4 切换 KRaft 模式:把 ZooKeeper 从依赖清单里划掉
如果你不想维护 ZooKeeper,直接上 KRaft 模式。以 bitnami 镜像为例,单机 KRaft 启动命令如下:
docker run -d --name kafka \ --network kafka-network \ -p 9092:9092 \ -e KAFKA_CFG_NODE_ID=1 \ -e KAFKA_CFG_PROCESS_ROLES=broker,controller \ -e KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093 \ -e KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092 \ -e KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER \ -e KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT \ -e KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=1@kafka:9093 \ -e KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \ -e ALLOW_PLAINTEXT_LISTENER=yes \ bitnami/kafka:3.6.0这里值得说明的是:KRaft 模式下,每个 Kafka 节点既可以是纯 broker,也可以是 broker 兼任 controller。KAFKA_CFG_CONTROLLER_QUORUM_VOTERS定义了 controller 节点列表,单机模式就指向自己。
bitnami 镜像会自动处理 KRaft 存储目录的格式化。如果用的是apache/kafka官方镜像,则必须手动执行kafka-storage.sh format格式化后才能启动,这一步很多人忘掉,导致容器启动后立刻退出。
验证方式和 ZooKeeper 模式完全一样,创建主题、收发消息即可。你会发现 KRaft 模式少了一个容器,排查问题时少了一堆可能性。
3. 配置背后的事:Advertised Listeners、持久化与内存
3.1 Advertised Listeners 决定生死的秘密
前文我一直强调ADVERTISED_LISTENERS,这是 Kafka 和大多数中间件最不一样的地方。我打个比方:LISTENERS是 broker 自己家开的那扇门,ADVERTISED_LISTENERS是贴在门口的名片,上面写着"我家在哪个地址"。
如果名片上的地址写错了,别人即使找到正确的 IP 和端口,也会被反复引到错误的地方。
不同场景下这张名片应该怎么写,我给你一张对照表:
| 客户端所在位置 | LISTENERS 配置 | ADVERTISED_LISTENERS 配置 |
|---|---|---|
| 本机测试 | PLAINTEXT://:9092 | PLAINTEXT://localhost:9092 |
| 局域网内其他机器 | PLAINTEXT://0.0.0.0:9092 | PLAINTEXT://宿主机IP:9092 |
| 云服务器公网访问 | PLAINTEXT://0.0.0.0:9092 | PLAINTEXT://公网IP或域名:9092 |
| Docker 网络内的其他服务 | PLAINTEXT://:9092 | PLAINTEXT://kafka容器名:9092 |
一个典型错误:在宿主机上用-p 9092:9092做了端口映射,但ADVERTISED_LISTENERS写的是容器内 IP,此时容器外客户端连不上,容器内却一切正常。排查这个问题的核心思路就是:先确认客户端拿到的 broker 地址是什么,再对照它是否真的能路由到 broker。
3.2 持久化:容器可以随便删,数据不能丢
Kafka 容器默认把数据写在自己的容器层里,容器一删,数据全没。所以生产环境必须挂载数据卷。
用 docker run 启动时这样加参数:
-v kafka_data:/bitnami/kafkaZooKeeper 需要单独挂载自己的数据目录:
-v zookeeper_data:/bitnami/zookeeper不同镜像的数据目录不一样,这个细节经常害人:
| 镜像 | 数据目录 |
|---|---|
| bitnami/kafka | /bitnami/kafka |
| apache/kafka | /tmp/kraft-logs(KRaft 模式默认路径) |
| confluentinc/cp-kafka | /var/lib/kafka/data |
挂载路径写错的典型症状是:容器起来了、数据看起来也正常,但挂载的卷是空的,Kafka 实际还在写容器内部目录。检查方法很简单,往主题里发几条消息,然后进入宿主机卷目录,看看有没有实际文件生成。
3.3 内存与文件描述符:Docker 限制和 JVM 参数要一起调
Kafka 是 Java 应用,跑在 JVM 上。Docker 里给它设置内存限制时,一定要和 JVM 堆大小匹配起来。
开发机单机测试,堆内存默认够用;生产环境建议显式设置:
-e KAFKA_HEAP_OPTS="-Xmx4g -Xms4g"同时 Docker 层面的内存限制要留出堆外内存余量。比如 JVM 堆给 4G,容器内存限制至少 6G,因为 Kafka 还要用堆外内存做页缓存和网络缓冲。如果容器内存上限恰好等于堆内存,系统会频繁触发 GC,甚至被 OOM Killer 干掉,表现就是 broker 时不时掉线。
文件描述符限制也值得检查。Kafka 客户端连接多、日志文件多,对文件句柄消耗很大。宿主机上调整方法因系统而异,但 Docker 层可以设置:
ulimits: nofile: soft: 65536 hard: 65536如果你看到日志里出现 "Too many open files",十有八九就是这个问题。
4. 生产环境的三节点集群:从规划到验证
4.1 先想清楚节点分配再写编排文件
Kafka 集群的节点数规划,我最常被问到的问题是:"两个 broker 够吗?" 我的回答是:至少三个。原因很简单,Kafka 的副本机制默认要向 ISR(同步副本集合)写入成功后才确认,副本数少了,一点故障就会导致可用性受损。
三节点的标准分配方式有两种:
- 3 个节点都是 broker 兼任 controller,适合中小规模集群。
- 3 个 controller 节点 + 3 个 broker 节点,适合大集群,职责分离。
我自己搭建测试集群时用第一种。多节点不使用 ZooKeeper,而是直接用 KRaft 模式,这样整个集群只有 3 个容器,逻辑清晰。
4.2 三节点 KRaft 集群的 docker-compose 配置
下面的编排文件可以直接保存为docker-compose.yml:
version: "3.8" networks: kafka-cluster: driver: bridge volumes: kafka1_data: kafka2_data: kafka3_data: services: kafka1: image: bitnami/kafka:3.6.0 container_name: kafka1 networks: - kafka-cluster ports: - "19092:9092" volumes: - kafka1_data:/bitnami/kafka environment: KAFKA_CFG_NODE_ID: 1 KAFKA_CFG_PROCESS_ROLES: broker,controller KAFKA_CFG_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093 KAFKA_CFG_ADVERTISED_LISTENERS: PLAINTEXT://localhost:19092 KAFKA_CFG_CONTROLLER_LISTENER_NAMES: CONTROLLER KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT KAFKA_CFG_CONTROLLER_QUORUM_VOTERS: 1@kafka1:9093,2@kafka2:9093,3@kafka3:9093 KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR: 3 KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 3 KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR: 2 ALLOW_PLAINTEXT_LISTENER: "yes" kafka2: image: bitnami/kafka:3.6.0 container_name: kafka2 networks: - kafka-cluster ports: - "29092:9092" volumes: - kafka2_data:/bitnami/kafka environment: KAFKA_CFG_NODE_ID: 2 KAFKA_CFG_PROCESS_ROLES: broker,controller KAFKA_CFG_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093 KAFKA_CFG_ADVERTISED_LISTENERS: PLAINTEXT://localhost:29092 KAFKA_CFG_CONTROLLER_LISTENER_NAMES: CONTROLLER KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT KAFKA_CFG_CONTROLLER_QUORUM_VOTERS: 1@kafka1:9093,2@kafka2:9093,3@kafka3:9093 KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR: 3 KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 3 KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR: 2 ALLOW_PLAINTEXT_LISTENER: "yes" kafka3: image: bitnami/kafka:3.6.0 container_name: kafka3 networks: - kafka-cluster ports: - "39092:9092" volumes: - kafka3_data:/bitnami/kafka environment: KAFKA_CFG_NODE_ID: 3 KAFKA_CFG_PROCESS_ROLES: broker,controller KAFKA_CFG_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093 KAFKA_CFG_ADVERTISED_LISTENERS: PLAINTEXT://localhost:39092 KAFKA_CFG_CONTROLLER_LISTENER_NAMES: CONTROLLER KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT KAFKA_CFG_CONTROLLER_QUORUM_VOTERS: 1@kafka1:9093,2@kafka2:9093,3@kafka3:9093 KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR: 3 KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 3 KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR: 2 ALLOW_PLAINTEXT_LISTENER: "yes"启动命令:
docker compose up -d然后是三个节点的关键配置说明:
KAFKA_CFG_NODE_ID:每个节点在集群里的唯一标识,必须不同。KAFKA_CFG_CONTROLLER_QUORUM_VOTERS:三个节点互相组成 controller 选举组,任何一个挂掉另外两个还能继续选主。KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR:offsets 主题是消费者提交位移的地方,副本数设为 3,避免单点丢失。ADVERTISED_LISTENERS这里写的是localhost:19092等宿主机映射端口,适合在本机验证。如果客户端在别的机器,需要把 localhost 替换为宿主机地址。
4.3 多副本主题的实际验证
集群启动后,进入任一节点验证。
docker exec -it kafka1 bash cd /opt/bitnami/kafka/bin创建一个 3 分区、3 副本的主题:
kafka-topics.sh --bootstrap-server localhost:19092 \ --create --topic cluster-test \ --partitions 3 --replication-factor 3查看主题详情:
kafka-topics.sh --bootstrap-server localhost:19092 --describe --topic cluster-test正常输出里,每个分区的Leader应该分散落在三台 broker 上,Replicas和Isr列表都包含三个节点编号。如果某个分区的 Isr 列表少于 Replicas,说明同步没跟上,多半是网络或 IO 问题。
然后做最关键的故障演练:把 kafka3 容器停掉,再看主题状态:
docker stop kafka3 kafka-topics.sh --bootstrap-server localhost:19092 --describe --topic cluster-test你会发现剩下的两个副本自动把分区 Leader 接了过去,消息读写依然正常。这就是 Kafka 副本机制的意义,也是验证集群安装是否合格的标准动作。
5. 踩坑实录:几类常见问题的完整排查链路
5.1 客户端报 Connection refused,容器却看不出任何问题
这是我遇到最多的故障,也是典型"假活"问题。
完整排查链路如下:
# 1. 确认容器确实在运行 docker ps # 2. 看 broker 日志有没有异常 docker logs kafka --tail 100 # 3. 进入容器看实际监听端口 docker exec -it kafka bash ss -lnt # 4. 查看当前广播地址配置 env | grep ADVERTISED如果能监听到 9092,但客户端连不上,问题几乎都出在ADVERTISED_LISTENERS。你拿到的地址可能是一个容器内 IP,也可能是一个你根本访问不到的 hostname。
换个思路更快的诊断方法:用kafka-broker-api-versions.sh从客户端视角看一下 broker 广播的地址:
docker exec -it kafka bash cd /opt/bitnami/kafka/bin kafka-broker-api-versions.sh --bootstrap-server localhost:19092这个命令成功的话,会返回 broker 的版本信息。如果失败,报错信息里会直接给出它尝试连接的真实地址——那个地址就是问题所在。
5.2 容器启动顺序导致的 ZooKeeper 连接超时
用 docker-compose 启动老架构时,Kafka 容器总是比 ZooKeeper 先退出,报错信息是:
Connection to zookeeper lost. Shutting down.新手会以为端口没映射好,其实原因是depends_on只保证容器的启动顺序,不保证服务真正就绪。ZooKeeper 容器虽然起来了,但内部服务还没完成初始化,Kafka 就去连接,结果失败退出。
解决办法是给 ZooKeeper 加健康检查,让 Kafka 等到检查通过后再启动:
services: zookeeper: healthcheck: test: ["CMD", "zkServer.sh", "status"] interval: 10s timeout: 5s retries: 5 kafka: depends_on: zookeeper: condition: service_healthyKRaft 模式没有 ZooKeeper,这个坑天然规避了。这也是我推荐新项目直接用 KRaft 的另一个理由。
5.3 容器一重建数据就全没了
这是一个让我印象非常深刻的教训。某个测试环境里,Kafka 跑得好好的,维护人员顺手docker compose down清理环境,再up -d起来,所有主题全空了。原因很简单:编排文件里没有挂数据卷。
还有更隐蔽的版本——挂载路径写错了。比如用官方镜像却写了/bitnami/kafka,Kafka 实际数据写在/tmp/kraft-logs,卷目录下什么都没有,表面看挂载成功了,实际上数据根本没持久化。
排查方法:切到宿主机卷目录,查看目录大小和文件结构。正常情况应该能看到大量.log结尾的日志段文件,如果目录是空的,立刻检查镜像对应的实际数据目录。
5.4 高并发下 broker 接二连三掉线
如果集群在业务高峰时段出现节点轮番重启,日志里有 OOM 关键字,那就要同时检查 JVM 堆设置和容器内存限制。
常见错误是只设置了容器内存上限,没调 JVM 堆大小。默认 JVM 堆只有物理内存的四分之一,在容器里这么算经常偏小,GC 频繁,延迟飙升。
建议经验值:容器内存 6G 时,JVM 堆设 4G;容器内存 8G 时,堆设 5G 到 6G。同时打开 GC 日志,方便事后分析。
GC 日志是最容易忽略的排障抓手。很多人纠结 Kafka 重启的根本原因,其实 GC 日志早就把线索写在里面了。5.5 磁盘被日志段塞满
Kafka 的消息以日志段(segment)文件的形式落盘。默认保留策略是 7 天,但如果你测试环境里疯狂往主题里写数据,磁盘照样会被塞满。
解决思路有两个层面。一是全局调整保留策略:
KAFKA_CFG_LOG_RETENTION_HOURS=24二是针对特定主题调整清理策略:
kafka-configs.sh --bootstrap-server localhost:19092 \ --alter --entity-type topics \ --entity-name cluster-test \ --add-config retention.ms=3600000生产环境我建议对不同的主题设置差异化保留时间:日志审计类主题保留 30 天,业务消息类 3 天,指标类 1 天。全集群一个保留策略看起来省事,实际上既浪费磁盘又容易误删关键数据。
6. 装完只是开始:管理界面、监控和日常检查
6.1 可视化界面:Kafka-UI、Kafdrop 和 AKHQ
命令行能搞定所有操作,但团队成员协作时,可视化界面大大降低使用门槛。我自己常用的几个如下:
| 工具 | 特点 | 适合场景 |
|---|---|---|
| Kafka-UI | 功能全面,支持主题管理、消费组查看、消息浏览 | 团队日常使用首选 |
| Kafdrop | 轻量、界面简洁 | 只想快速看主题和消息时 |
| AKHQ | 功能丰富,偏重管理操作 | 运维管理场景 |
给一个 Kafka-UI 的 docker-compose 片段,可以直接接在你现有的 compose 文件后面:
kafka-ui: image: provectuslabs/kafka-ui:latest container_name: kafka-ui networks: - kafka-cluster ports: - "8080:8080" environment: KAFKA_CLUSTERS_0_NAME: local KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka1:9092 KAFKA_CLUSTERS_0_KAFKACONFIG_ACKS: all启动后浏览器访问http://localhost:8080,就能看到集群状态、主题列表、消费者组偏移量。它比命令行直观得多,特别适合刚接手 Kafka 的人快速建立全局认知。
6.2 监控组合:JMX exporter + Prometheus + Grafana
安装 Kafka 只是起点,真正让它稳定运行需要一套监控。
标准做法是用 JMX exporter 暴露 Kafka 指标,Prometheus 采集,Grafana 出面板。关键的监控指标包括:
- Broker 在线状态和 controller 选举情况。
- 请求处理的平均延迟和队列积压。
- 消费者组的 lag(消费落后量),这是最需要关注的,消息堆积往往从这里先暴露。
- 磁盘使用率和消息入站速率。
你可以在每个 Kafka 容器里加一个 JMX exporter 边车容器,也可以通过 Kafka 自带的 JMX 端口直接暴露指标。社区里有很多现成的 Grafana dashboard,导入后基本不用自己画图。
6.3 我个人的日常检查清单
最后整理一下我日常维护 Kafka 时固定会过一遍的检查项:
- 每个节点
docker ps状态是否 Up,健康检查是否通过。 - 日志中是否有
ERROR级别告警,重点看Controller相关报错。 - 磁盘剩余空间是否低于阈值。
- 用
kafka-consumer-groups.sh --describe检查每个消费组的 lag。 - 主题分区数、副本数是否还在预期范围。
这套清单看起来简单,但每次都能在问题扩大前发现苗头。Kafka 安装在 Docker 里的难度不在"启动容器",而在"让它长期稳定地跑下去"。按照上面的步骤把单机、集群都过一遍,再把这个检查清单挂到日常运维里去,相信你很快就能从一个"把 Kafka 装起来的人",变成"真正运维 Kafka 的人"。