揭秘 Kafka 的恰好一次语义:一份综合指南
通过幂等生产者、事务、read_committed消费者和偏移量提交,理解Kafka的精确一次语义。
解密Kafka的精确一次语义:全面指南
Kafka的精确一次语义可以在生产者重试、代理故障转移或应用程序重启时,保护流处理管道免受重复输出记录的影响。这种保证很强大,但比字面意思要窄:Kafka可以使Kafka写入和消费的偏移量具有事务性。它无法自动使你的外部数据库、支付网关或HTTP API实现精确一次。
当重复输出代价高昂或难以清理时,使用精确一次语义,例如库存调整、账户余额事件或由其他服务消费的派生状态主题。
通俗解释交付保证
Kafka应用程序通常讨论三种交付模型。
- 至多一次:你的应用可能会丢失记录,但不应处理同一条记录两次。当偏移量在处理完成之前提交时,可能会发生这种情况。
- 至少一次:你的应用不应丢失记录,但在重试或重启后可能会多次处理同一条记录。
- 精确一次:Kafka的读取-处理-写入循环将其输出记录和消费的偏移量作为一个事务提交。
最后一点是关键。当应用程序从Kafka读取数据,将结果写回Kafka,并在同一事务中提交偏移量时,精确一次语义最强。
幂等生产者
幂等生产者防止由生产者重试引起的重复写入。Kafka为生产者分配一个ID,并跟踪每个生产者和分区的序列号。如果代理已经接受了一个批次,然后收到重试请求,它可以拒绝重复的批次,而不是再次追加。
对于当前的Kafka客户端,当你没有配置冲突的生产者设置时,幂等性默认启用。你仍然可以显式设置它:
enable.idempotence=true
acks=all
acks=all意味着领导者在确认写入之前等待所有同步副本。幂等性还依赖于兼容的重试和飞行中请求设置,因此除非你了解在你的客户端版本中的影响,否则避免覆盖生产者可靠性设置。
幂等性保护生产者重试,但不能使整个处理工作流原子化。如果你的应用从一个主题消费并生产到另一个主题,你需要事务来将输出和偏移量提交绑定在一起。
Kafka事务
事务允许一个生产者将多个写入分组为一个原子单元。生产者需要一个稳定的transactional.id。
transactional.id=inventory-adjuster-0
enable.idempotence=true
acks=all
典型的事务流程是:
- 应用程序启动时初始化事务。
- 开始一个事务。
- 从输入主题消费记录。
- 生产输出记录。
- 将消费的偏移量发送到事务中。
- 提交事务,或在失败时中止。
如果进程在提交前崩溃,Kafka不会将未提交的输出暴露给read_committed消费者。重启后,应用程序可以再次读取相同的输入记录,并产生一个已提交的结果。
重要的消费者设置
读取事务性输出的消费者应使用:
isolation.level=read_committed
enable.auto.commit=false
read_committed隐藏来自已中止事务的记录。enable.auto.commit=false防止消费者在事务外部提交偏移量。
属性名称很重要。Kafka的消费者设置是enable.auto.commit,而不是auto.commit.enable。
对于手动消费者-生产者应用程序,偏移量提交必须是生产者事务的一部分。在Java客户端中,这意味着使用事务性生产者API,包括在提交事务之前将偏移量发送到事务中。
具体场景
想象一个orders主题和一个inventory-events输出主题。你的服务读取一个订单,检查SKU,并写入一个库存扣减事件。
没有事务时,在写入输出后但在提交输入偏移量前崩溃,重启后可能会创建重复的扣减。有了事务,输出事件和输入偏移量提交要么一起成功,要么一起失败。重启可能会重新读取订单,但只有一个已提交的库存事件对下游的read_committed消费者可见。
需要注意的限制
Kafka的精确一次语义不涵盖Kafka之外的副作用,除非你为此设计。如果同一个服务也写入PostgreSQL或调用计费API,该外部副作用需要自己的幂等键、唯一约束、事务策略或发件箱模式。
事务还会增加协调开销。对于简单的日志摄取,如果重复是可接受的,幂等生产者加上至少一次消费者可能就足够了。
实用检查清单
为每个应用程序实例或任务使用稳定的transactional.id。不要让两个活跃的生产者同时使用相同的transactional ID。
将事务性输出的消费者设置为read_committed。在事务性处理循环中禁用自动偏移量提交。
保持事务简短。大型事务可能会增加延迟并使恢复变慢。
单独处理外部系统。Kafka可以保护Kafka状态,但你的数据库写入仍然需要幂等设计。
有用的要点:精确一次语义不是魔法开关。它们是一组生产者、消费者和事务选择,最适合Kafka到Kafka的流处理。