NewSyncProducer 默认阻塞且无超时控制,易因网络或broker问题卡死goroutine;必须设Timeout≤5s并慎用RequiredAcks,推荐改用AsyncProducer实现非阻塞发送。

直接用 Sarama 实现 Kafka 生产者和消费者,关键不是“能不能”,而是“怎么避开它默认的同步阻塞陷阱和配置坑”。Sarama 的 NewSyncProducer 看似简单,但默认会卡住整个 goroutine;而 NewConsumer 默认不支持自动提交 offset,一不留神就重复消费。
为什么不能直接用 NewSyncProducer 发送消息?
Sarama 的同步生产者在调用 SendMessage 时,会等待 broker 返回 ACK,且内部没有超时控制(除非显式配置)。一旦网络抖动或 broker 不可用,它会一直阻塞,连带拖垮整个服务。
- 必须设置
config.Producer.Timeout(建议 ≤ 5s),否则可能卡死 -
config.Producer.RequiredAcks推荐用kafka.NoResponse或kafka.WaitForLocal,避免等所有副本确认 - 更稳妥的做法是改用
NewAsyncProducer+ channel 消费Successes和Errors,把发送逻辑非阻塞化
消费者如何避免重复消费和 offset 提交混乱?
Sarama 的 NewConsumer 是低阶 API,不管理 offset 自动提交、分区重平衡或会话心跳。你得自己维护 offset 存储(比如写入本地文件或 Redis),否则重启后从头开始消费。
- 用
NewConsumerGroup替代NewConsumer,它内置了 group 协议支持和 offset 自动提交(需开启config.Consumer.Offsets.AutoCommit.Enable = true) - 注意
config.Consumer.Offsets.Initial:设为kafka.OffsetNewest才能从最新消息开始,而不是默认的OffsetOldest - 如果手动管理 offset,务必在
session.MarkOffset后调用session.Commit,否则只是内存标记,不持久化
如何正确处理 Sarama 的重试和错误?
Sarama 不会自动重试失败的生产请求,也不会帮你区分可恢复错误(如 kafka.ErrNotLeaderForPartition)和不可恢复错误(如 kafka.ErrMessageSizeTooLarge)。
- 对
AsyncProducer.Errors()channel 中的错误,先判断err.(kafka.KError)类型再决定是否重发 - 消费者中遇到
kafka.ErrUnknownTopicOrPartition,通常是 topic 不存在或 metadata 没刷新,应触发client.RefreshMetadata - 不要忽略
consumer.Close()—— 它会触发一次 final offset commit,否则可能丢失最后一批 offset
真正难的不是写通代码,而是理解 Sarama 把 Kafka 的分布式语义(如 ISR、rebalance、commit 策略)全暴露给了你。一个没配对的 RequiredAcks 和 Timeout,或者漏掉一次 MarkOffset,就足以让线上行为变得不可预测。



















