Sunday面试指南

Kafka 的 Exactly-once 是什么?幂等生产者和事务能保证数据库只写一次吗?

下面是一段教学模拟,不是真实面试记录。

🧑‍💻 面试官:Kafka 支持 Exactly-once,消费后写数据库,还需要幂等吗?

🙋‍♂️ 我:应该不用,消息只处理一次。

🧑‍💻 面试官:数据库已经提交,提交消费位点前进程退出,重启后会不会再读这条消息?

🙋‍♂️ 我:会,这两次提交不在同一个事务里。

🧑‍💻 面试官:那 Kafka 事务覆盖什么,幂等生产者又解决哪类重复?

Exactly-once 必须说明「在哪个范围内」。Kafka 事务不会自动把外部数据库加入同一次原子提交。

面试速答(60 秒版)

Kafka 幂等生产者主要防止生产重试在相应分区内产生重复记录,不等于自动识别应用重复提交的同一笔业务。

Kafka 事务可以把相关 Kafka 输出和消费位点组合提交,配合 read_committed 等条件,构建 Kafka 内部的恰好一次处理效果。

但消费消息后写外部数据库,数据库提交与 Kafka 位点提交仍可能分开。数据库成功、位点未提交,消息重读时就可能再次写入。

因此,外部写入通常还需要稳定业务键、唯一约束与事务内幂等处理,或采用明确支持的一致性方案。不能只打开 Kafka 事务,就宣布所有系统都只执行一次。

Kafka:恰好一次的范围:Kafka事务不自动包含数据库

知识点详解:先把一次处理画成几次提交

幂等生产者处理的是生产重试

假设生产者发出记录,Broker 保存了,但响应丢失。生产者重试时,需要避免同一次发送产生重复记录。

幂等生产机制借助生产者身份与序列等信息处理这类情况。它不根据消息正文猜测两个订单是不是同一笔。

应用主动调用两次发送,不能默认被当成一次网络重试去重。业务唯一性与生产层幂等仍是两件事。Kafka 设计文档

Kafka 事务可以把输出与位点放在一起

假设应用从输入 Topic 读取消息,计算后写到输出 Topic,再推进输入消费位点。

事务可以让这一组 Kafka 操作作为一个提交单元。消费者还要使用相应读取模式,让未提交或中止事务的输出不被当成已提交结果。消费配置说明

这不是所有程序指令只运行一次。失败后代码可能重跑,但对外可见效果在约定范围内保持一致。

外部数据库存在一个提交窗口

假设消费消息 M 后更新数据库:

时点数据库Kafka 位点
读到 M尚未修改未推进
数据库提交修改已生效未推进
此时退出修改仍存在M 可能再次被消费
重启重读 M直接再写可能重复后续才提交

先提交位点也有问题:位点成功、数据库还没写时退出,可能漏掉业务处理。

所以不能靠调整先后顺序消除所有窗口。两次独立提交,需要额外设计。

数据库成功,位点没提交:独立提交存在重读窗口

幂等记录要与业务变化一起成立

常见方案使用稳定业务 ID,在数据库事务内确认是否已处理,并执行业务变更,结合唯一约束防止并发重复。

如果在内存里记录已处理,重启后就可能丢失。如果先单独提交幂等标记、业务随后失败,也会留下“记成完成、实际没做”的记录。

关键不是有一张去重表,而是标记与业务结果怎样一致提交。外部支付、邮件还需要对应机制,数据库幂等不自动涵盖它们。

幂等标记和业务变化一起提交:标记和结果保持一致

面试官继续追问

Exactly-once 是不是消息只能在网络上传一次?

不是。重试和重放可能发生,讨论的是约定范围内可见效果。应说明成立条件,不是字面解释一次传输。

每次生成一个新随机去重键,行不行?

重试时换新键,就无法识别同一笔业务。需要稳定、对应操作语义的身份。

数据库与邮件能一起保证吗?

不能凭 Kafka 或本地数据库事务自动保证。应分别设计可靠投递、状态与幂等,明确结果未知时怎样恢复。

面试速记卡

  • 幂等生产者:处理相应生产重试,不自动去重所有业务重复。
  • Kafka 事务:组合 Kafka 输出与消费位点等操作。
  • 读取条件:配合 read_committed 等配置核对可见结果。
  • 外部数据库:独立提交存在重读与重复写入窗口。
  • 业务幂等:稳定身份、唯一约束及一致的事务规则。

公司面试真题

真题根据求职者公开面经整理,题意经过概括,非逐字原话或公司官方题库;本文为 Sunday 的独立解析。

  • 美团 · Java后端 · 实习

    Kafka 如何保证消费不丢失且不重复?(题意整理)

    4.21美团Java实习一二面面经 ↗
    面试记录为 2020-04-21、2020-04-24;原帖编辑于 2020-11-14

浏览公司面试真题 →
简历汪永久免费在线制作简历,模板直接套用、导出无水印,永久免费、下载免费,不需要付费解锁任何功能。去写简历