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