ConsumerBuilder 构造消费者时,为什么用 Ignore
而不是 Null
?
Ignore而不是
Null?
因为 Kafka 消费者默认不关心消息的 key(比如你没用 key 做分区路由或去重),而
Ignore表示“跳过反序列化 key”,比
Null更安全——
Null会尝试反序列化为
null,但若 broker 发来非空 key,就可能抛
SerializationException。实际项目中,只要你不显式读取
cr.Key,就该用
Ignore。
AutoOffsetReset.Earliest
和 Latest
的真实行为差异
这个配置只在 consumer group 第一次消费某个 topic、或 offset 丢失/过期时生效。它不是“每次启动都从头/尾开始”,而是“没有有效提交 offset 时才触发”。常见误判是:以为设了
Earliest就能反复重放历史消息——其实一旦成功 commit 过 offset,后续启动永远从上次位置继续。
Earliest:无 offset 时从最早可用消息开始(注意:不是 topic 创建时刻,而是当前保留窗口内的最早)
Latest:无 offset 时只消费启动后新写入的消息 真正想重放?得删掉 group 或调用
consumer.Unsubscribe()+
consumer.Subscribe()后手动
Seek()
为什么 Consume()
要包在 try/catch(ConsumeException)
里?
Consume()是阻塞调用,但底层网络抖动、broker 临时不可达、SASL 认证失败等都会直接抛
ConsumeException,而不是返回 null 或 timeout。不捕获会导致进程意外退出。更关键的是:某些错误(如
GroupAuthorizationFailed)是 fatal 的,必须靠
c.OnError监听并主动退出循环,否则 consumer 会卡死在无效状态。
consumer.OnError += (_, e) => {
if (e.IsFatal) consuming = false; // 必须终止循环
Console.WriteLine($"Kafka error: {e.Reason}");
};
EnableAutoCommit = false
时,Commit()
的调用时机很关键
手动 commit 是为了防止消息重复消费或丢失,但 commit 太早(比如刚收到就 commit)= 消息处理失败后无法重试;commit 太晚(比如攒 10 条再 commit)= 进程崩溃时最多丢 10 条。真实建议:
业务逻辑成功执行完、且结果持久化(如 DB 写入成功)后再调用consumer.Commit(cr)不要在循环里每条都 commit——性能差;也不要攒太多——风险高;折中方案是每 5–10 条或每 1–2 秒 commit 一次 注意:
Commit()是异步的,如果要确保落盘,得等
consumer.Commit().Wait()(仅调试用,生产慎用) Kafka 消费不是“启个循环就完事”,
Consume()的阻塞特性、offset 提交时机、错误恢复路径,三者稍有错位就会导致消息积压、重复或丢失——尤其在服务重启、网络分区、topic 分区扩容等真实场景下,这些细节比语法更重要。
