Kafka 系列 幂等与事务

深入理解Kafka

Posted by lichao modified on September 10, 2020

Kafka 从0.11.0.0版本开始引入了幂等和事务这两个特性,以此来实现EOS(exactly once semantics ,精确一次处理语义)。

幂等

所谓的幂等,简单地说就是对接口的多次调用所产生的结果和调用一次是一致的。生产者在进行重试的时候有可能会重复写入消息,而使用 Kafka 的幂等性功能之后就可以避免这种情 况。

开启幂等性功能的方式很简单,只需要显式地将生产者客户端参数 enable.idempotence 设置为 true 即可(这个参数的默认值为false )

为了实现生产者的幂等性, Kafka为此引入了producer id(以下简称PID)和序列号(sequence number)这两个概念。

每个新的生产者实例在初始化的时候都会被分配一个PID ,这个 PID 对用户而言是完全透明的。对于每个PID,消息发送到的每一个分区都有对应的序列号,这些序列号从0开始单调递增。生产者每发送一条消息就会将<PID,分区>对应的序列号的值加 1。

broker 端会在内存中为每一对<PID,分区>维护一个序列号。对于收到的每一条消息,只有当它的序列号的值(SN_new)比 broker 端中维护的对应的序列号的值(SN_old)大 1(即SN_new = SN_old + 1)时, broker 才会接收它。如果 SN_new < SN_old + 1, 那么说明消息被重复写入,broker 可以直接将其丢弃。如果 SN_new > SN_old + 1,那么说明中间有数据尚未写入,出现了乱序,暗示可能有消息丢失,对应的生产者会抛出OutOfOrderSequenceException,这个异常是一个严重的异常,后续的诸如send()、beginTransaction()、commitTransaction()等方法的调用都会抛出IllegalStateException的异常。

引入序列号来实现幕等也只是针对每一对<PID,分区>而言的,也就是说, Kafka 的幂等只能保证单个生产者会话( session )中单分区的幂等。

事务

幂等性并不能跨多个分区运作,而事务可以弥补这个缺陷。事务可以保证对多个分区写入操作的原子性。操作的原子性是指多个操作要么全部成功,要么全部失败,不存在部分成功、部分失败的可能。