1. docker‑compose 部署 3 节点 Kafka 集群(端口映射场景)
完全可以在docker-compose.yml直接配置,不需要修改容器内 server.properties 文件,通过环境变量直接注入 kafka 配置。
Kafka 官方镜像规则:配置文件里的参数,全部转大写、点改成下划线,作为环境变量。
advertised.listeners → KAFKA_ADVERTISED_LISTENERS
listeners → KAFKA_LISTENERS
⚠️重点:3 个 broker,每个 broker 的KAFKA_ADVERTISED_LISTENERS只填自己【宿主机映射 IP: 映射端口】,不能写全部 3 个节点
KAFKA_LISTENERS 写容器内部 0.0.0.0:9092
客户端连接的bootstrap.servers填全部 3个宿主机映射地址,这个是客户端参数,不是 compose 里 kafka 的环境变量
broker 宿主机 IP 宿主机映射端口 容器内端口 broker.id
broker‑1 10.0.0.10 19092 9092 1
broker‑2 10.0.0.11 19093 9092 2
broker‑3 10.0.0.12 19094 9092 3
docker-compose.yml 示例(单宿主机多端口映射,多宿主机看下面)
注意:如果 3 台 kafka 是分布在 3 台不同宿主机,一套 compose 只能管理一台,
需要每台机器单独一份 compose;下面示例是同一台机器启动 3 个 kafka 容器。
version: '3.8'
services:
zookeeper:
image: confluentinc/cp-zookeeper:7.5.0
hostname: zookeeper
ports:
- "2181:2181"
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
kafka-broker1:
image: confluentinc/cp-kafka:7.5.0
hostname: kafka-broker1
ports:
- "19092:9092" #宿主机端口:容器内部端口
depends_on:
- zookeeper
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092
# 只写自己的宿主机映射地址!!
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://10.0.0.10:19092
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 3
kafka-broker2:
image: confluentinc/cp-kafka:7.5.0
hostname: kafka-broker2
ports:
- "19093:9092"
depends_on:
- zookeeper
environment:
KAFKA_BROKER_ID: 2
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://10.0.0.11:19093
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 3
kafka-broker3:
image: confluentinc/cp-kafka:7.5.0
hostname: kafka-broker3
ports:
- "19094:9092"
depends_on:
- zookeeper
environment:
KAFKA_BROKER_ID: 3
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://10.0.0.12:19094
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 3
客户端连接参数(外部业务)
bootstrap.servers=10.0.0.10:19092,10.0.0.11:19093,10.0.0.12
2. Kafka 消费不到数据,抓包可以做
Kafka 消费不到数据,抓包可以做,但不能只靠抓包
抓包适合排查网络层问题;但 kafka 消费失败很多是协议、元数据、配置问题,抓包看到 TCP 通,也可能消费不到消息。
✅什么时候适合抓包
1.客户端完全连不上 broker、报连接超时、connection refused
2.怀疑端口映射 / 防火墙 / NAT/advertised.listeners 导致网络跳转异常(正好你是 docker + 端口映射场景,这个场景非常适合抓包)
3.怀疑丢包、TCP 重置、访问被拦截
工具:tcpdump、wireshark
抓包位置有三个关键点,这是 docker 端口映射场景最重要:
1.消费客户端机器抓包:看客户端发出去的请求,收到的返回是什么
2.kafka 宿主机抓包(不是容器内部!):看宿主机端口(比如 19092)有没有收到客户端流量,有没有回包
3.容器内部抓包(可选):看流量是否进到 kafka 容器 9092 端口
tcpdump 示例
# 在消费客户端机器抓包,抓访问kafka宿主机10.0.1.10 19092端口
tcpdump -i any host 10.0.0.10 and port 19092 -nn -w kafka_client.pcap
# 在kafka宿主机抓包,抓映射端口19092
tcpdump -i any port 19092 -nn -w kafka_host.pcap
把 pcap 拿 wireshark 打开,可以解析 kafka 协议,能看到:Metadata 请求、Fetch 请求(消费拉取请求)。
⚠️抓包看到 TCP 正常,依然消费不到数据(高频,你的 docker 映射场景极易踩坑)
TCP 能连通 ≠ kafka 协议正常工作。
典型现象:tcpdump 看到三次握手正常,但是没有 Fetch 请求,或者 Metadata 返回给客户端的是容器内部 IP。
👉 就是advertised.listeners配置错误!
1.客户端连接 10.0.0.10:19092,拿到 metadata 元数据,broker 返回容器内部 IP(172.xx)
2.客户端拿到容器内网 IP,尝试去连 172.x.x.x,外部机器访问不了,消费卡住,无报错或者报连接失败。
✨抓包看 Metadata 响应包,就能看到 broker 返回给客户端的是什么地址,这是 docker 端口映射排错的黄金手段。
📋消费不到数据完整排查顺序(优先顺序,建议按这个走)
第一步:确认 topic 是否真的有消息
# 在kafka集群侧查看topic消息数量
kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list xxx --topic your_topic
看 offset,确认 topic 有数据;注意:新消费者默认latest,如果没有新消息,消费不到旧数据。
检查消费者组 offset:
kafka-consumer-groups.sh --bootstrap-server xxx --group your_group --describe
看 CURRENT‑OFFSET / LOG‑END‑OFFSET,如果相等,代表没有可消费消息。
第二步:检查关键参数
1.auto.offset.reset:latest(只消费新消息) / earliest(从头消费),测试的时候设置 earliest。
2.确认 topic 分区数,消费者消费组的消费者数量不能大于分区数。
第三步:元数据问题(docker 端口映射最高概率)
抓包看客户端收到的 Metadata 响应,里面每个 broker 返回的 IP 端口,必须是客户端可以访问的宿主机映射 IP 端口,不能是容器 IP。
如果返回容器 IP,就是KAFKA_ADVERTISED_LISTENERS配置写错。
第四步:抓包排查网络
1.看是否发出 Fetch 请求(拉消息的请求)
• 没有 Fetch:元数据错误,客户端连不上真正 broker
• 有 Fetch 请求,但是返回空:topic 无数据、offset 已经到末尾、权限问题
2.看是否 TCP RST、丢包。
第五步:看日志
1.消费端应用日志,重点看 warn/error,很多人忽略客户端报错。
2.kafka broker 容器日志,看是否有权限、网络、异常报错。
🧩Wireshark 解析 Kafka 协议
打开 pcap 包:
Wireshark → 解析为 → Kafka,就可以直接看到 kafka 协议帧:
• MetadataRequest / MetadataResponse:元数据响应,查看 broker 返回的地址列表
• FetchRequest:消费者拉取消息请求
• FetchResponse:broker 返回给客户端的消息数据
常见现象根因
现象-----------------------根因
TCP 握手正常,但是没有 Fetch 请求 ----------- -Metadata 返回不可访问的容器 IP,advertised.listeners 错误
Fetch 请求发出,响应里面 records 为空 ------ -topic 没有消息、offset 已经消费完毕、auto.offset.reset=latest 没有新消息
抓包看到大量 TCP 重置 ----------- 防火墙 / 安全组拦截,端口映射异常
💡给你的实操建议
1.先不要上来就抓包,先执行脚本看 topic offset、消费组 offset,确认 topic 有数据。
2.如果 offset 显示有数据,客户端拿不到,优先怀疑 advertised.listeners,抓包看 Metadata 响应是最快定位手段。
3.如果 Metadata 返回的是宿主机映射 IP,再去排查客户端、权限、offset 重置策略。