Kafka 的 Docker 配置:一次点赞为什么会把 Kafka 内存打爆?
这篇笔记记录一次本地项目排障:知光后端在执行点赞 / 取消点赞时,Kafka 大量报错,最后定位到 Kafka Docker 配置不合理。
1. 现象
在后端日志里,先看到类似这样的错误:
Topic counter-events not present in metadata after 60000 ms
后来修复端口和 topic 后,又出现大量消费者组相关错误:
Unexpected error from SyncGroup:
The server experienced an unexpected error when processing the request.
Kafka 服务端日志里最终能看到真正的根因:
java.lang.OutOfMemoryError: Java heap space
也就是说,后端不是单纯代码异常,而是 Kafka broker 自己内存爆了。
2. 点赞为什么会用到 Kafka?
这个项目里,点赞不是简单地把数据库字段 like_count + 1。
它的流程大概是:
用户点赞 / 取消点赞
-> 后端修改 Redis 位图,记录这个用户是否点过
-> 后端发送一条 counter-events 消息到 Kafka
-> Kafka 消费者异步聚合点赞数
-> 聚合结果再写回 Redis 计数结构
这样设计的好处是:
- 点赞接口响应更快;
- 高频点赞不会每次都同步重算总数;
- 计数可以异步聚合,降低主链路压力。
所以,用户点一下赞,确实会触发 Kafka。
但是这次的问题不是“点赞消息太大”。
点赞消息本身可能只有几百字节,比如:
{
"entityType": "knowpost",
"entityId": "123",
"metric": "like",
"idx": 0,
"userId": 10001,
"delta": 1
}
它远远不到 1MB,更不可能自己撑爆 Kafka。
3. 第一层问题:端口和 advertised listener 不一致
一开始 Kafka Docker 配置里有一个关键错误:
KAFKA_CFG_ADVERTISED_LISTENERS: PLAINTEXT://10.13.1.5:9080
但是 Docker 实际暴露出来的端口是:
ports:
- ${HOST_IP}:${PANEL_APP_PORT_HTTP}:9092
.env 里:
PANEL_APP_PORT_HTTP=9092
也就是说:
真实可用地址:10.13.1.5:9092
Kafka 对外宣称:10.13.1.5:9080
这会导致客户端先连上 Kafka,但 Kafka 返回的 broker 地址是错的。于是后端会出现 metadata 超时、topic 找不到、消费者反复重连等问题。
修复方式是统一成 9092:
KAFKA_CFG_ADVERTISED_LISTENERS: PLAINTEXT://10.13.1.5:9092
后端也要对应:
spring:
kafka:
bootstrap-servers: 10.13.1.5:9092
4. 第二层问题:Kafka 内存配置不合理
端口修好以后,Kafka topic 能正常列出来:
canal-outbox
counter-events
但是消费者组仍然大量报错。继续看 Kafka 服务端日志,发现 broker 自己爆了:
java.lang.OutOfMemoryError: Java heap space
当时 Kafka 的配置大概是:
KAFKA_CFG_MESSAGE_MAX_BYTES: 524288000
KAFKA_CFG_FETCH_MESSAGE_MAX_BYTES: 524288000
KAFKA_CFG_PARTITION_FETCH_BYTES: 524288000
KAFKA_CFG_REPLICA_FETCH_MAX_BYTES: 524288000
KAFKA_CFG_MAX_REQUEST_SIZE: 524288000
KAFKA_HEAP_OPTS: -Xmx512m -Xms256m
这些数字里,524288000 大约等于 500MB。
翻译成人话:
Kafka 最多只有 512MB JVM 堆内存,
但是允许单条消息 / 单次请求 / 单次拉取达到 500MB。
这就像:
仓库总容量只有 512MB,
但允许单个包裹最大 500MB。
哪怕实际点赞消息很小,Kafka 在网络缓冲、消费者组协调、请求处理、元数据写入时,也可能围绕这些“最大上限”准备资源。再加上之前端口错误导致消费者频繁加入、离开、重平衡,最终 broker 的 group coordinator 处理消费者组状态时爆了堆内存。
5. 每个配置是什么意思?
KAFKA_CFG_MESSAGE_MAX_BYTES
KAFKA_CFG_MESSAGE_MAX_BYTES: 524288000
Kafka broker 允许单条消息最大约 500MB。
KAFKA_CFG_FETCH_MESSAGE_MAX_BYTES
KAFKA_CFG_FETCH_MESSAGE_MAX_BYTES: 524288000
消费者一次拉取消息时,允许从 broker 拿到最大约 500MB 的数据。
KAFKA_CFG_PARTITION_FETCH_BYTES
KAFKA_CFG_PARTITION_FETCH_BYTES: 524288000
消费者从单个分区一次最多拉取约 500MB。
KAFKA_CFG_REPLICA_FETCH_MAX_BYTES
KAFKA_CFG_REPLICA_FETCH_MAX_BYTES: 524288000
Kafka 副本之间同步数据时,一次最多拉取约 500MB。
单节点 Kafka 也可能保留这个配置,但本地开发一般不需要这么大。
KAFKA_CFG_MAX_REQUEST_SIZE
KAFKA_CFG_MAX_REQUEST_SIZE: 524288000
Kafka 允许客户端发来的单个请求最大约 500MB。
KAFKA_HEAP_OPTS
KAFKA_HEAP_OPTS: -Xmx512m -Xms256m
Kafka JVM 堆内存:
-Xms256m = 启动时先给 256MB 堆内存
-Xmx512m = 最多只能用 512MB 堆内存
这和上面的 500MB 请求上限明显不匹配。
6. 推荐修复配置
对于这个项目,点赞、收藏、outbox 事件都不应该是超大消息。开发环境可以把最大消息限制到 10MB,并把 Kafka heap 提高到 1GB。
推荐配置:
networks:
1panel-network:
external: true
services:
kafka:
container_name: ${CONTAINER_NAME}
deploy:
resources:
limits:
cpus: ${CPUS}
memory: ${MEMORY_LIMIT}
environment:
ALLOW_PLAINTEXT_LISTENER: "yes"
KAFKA_CFG_ADVERTISED_LISTENERS: PLAINTEXT://10.13.1.5:9092
KAFKA_CFG_CONTROLLER_LISTENER_NAMES: CONTROLLER
KAFKA_CFG_CONTROLLER_QUORUM_VOTERS: 0@127.0.0.1:9093
KAFKA_CFG_FETCH_MESSAGE_MAX_BYTES: 10485760
KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
KAFKA_CFG_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093
KAFKA_CFG_LOG_RETENTION_MS: 60000
KAFKA_CFG_MAX_REQUEST_SIZE: 10485760
KAFKA_CFG_MESSAGE_MAX_BYTES: 10485760
KAFKA_CFG_NODE_ID: 0
KAFKA_CFG_PARTITION_FETCH_BYTES: 10485760
KAFKA_CFG_PROCESS_ROLES: controller,broker
KAFKA_CFG_REPLICA_FETCH_MAX_BYTES: 10485760
KAFKA_HEAP_OPTS: -Xmx1g -Xms512m
image: bitnamilegacy/kafka:4.0.0
labels:
createdBy: Apps
networks:
- 1panel-network
ports:
- ${HOST_IP}:${PANEL_APP_PORT_HTTP}:9092
restart: always
其中:
10485760 = 10MB
这个大小对普通业务事件已经很宽松。
7. 修复后要验证什么?
1. Kafka broker 地址是否正确
应该看到 broker 是:
10.13.1.5:9092
而不是:
10.13.1.5:9080
2. topic 是否存在
至少需要:
counter-events
canal-outbox
其中:
counter-events:点赞、收藏等计数事件;canal-outbox:Canal 监听 outbox 表后转发的领域事件。
3. 后端是否读取了新配置
后端配置应该是:
spring:
kafka:
bootstrap-servers: 10.13.1.5:9092
如果改了 application.yml,要重新编译或重新启动后端,避免运行进程还读着旧配置。
4. Kafka 日志是否还出现 OOM
重点看有没有:
java.lang.OutOfMemoryError: Java heap space
如果还有,说明 Kafka 堆内存或容器内存仍然不够,或者还有异常大消息。
8. 这次学到的东西
这次问题很容易误判成:
点赞接口写错了
Kafka topic 没建
前端按钮有问题
但真正链路是:
点赞触发 Kafka 事件
-> Kafka advertised listener 配错端口
-> 客户端 metadata / consumer group 不稳定
-> Kafka 配置允许 500MB 超大请求,但 JVM heap 只有 512MB
-> broker 在消费者组协调时 OOM
-> 后端看到大量 SyncGroup / LeaveGroup 报错
所以排查 Kafka 问题时,要按顺序看:
- 客户端连接的是哪个
bootstrap-servers; - Kafka 对外宣称的
advertised.listeners是什么; - Docker 实际暴露的端口是什么;
- topic 是否存在;
- broker 自己有没有 OOM;
- 消费者组是否在反复 rebalance。
9. 一句话总结
这次不是“一个点赞消息太大”,而是:
Kafka 端口配置错 + 超大消息上限 + 很小的 JVM 堆内存
共同导致 Kafka broker 在消费者组协调时内存爆掉。

Kafka的docker配置
