Kafka--原理--幂等/事务

Posted IT利刃出鞘

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kafka--原理--幂等/事务相关的知识,希望对你有一定的参考价值。

原文网址:Kafka--原理--幂等/事务_IT利刃出鞘的博客-CSDN博客

简介

        本文介绍Kafka的幂等和事务的原理。

        Kafka通过幂等和事务这两个机制保证了精准一次(exactly once)。

消息传输保障

一般而言,消息中间件的消息传输保障有3个层级,分别如下。

  • at most once:至多一次。消息可能会丢失,但绝对不会重复传输。
  • at least once:最少一次。消息绝不会丢失,但可能会重复传输。
  • exactly once:恰好一次。每条消息肯定会被传输一次且仅传输一次。

        通常情况下,为保证消息不丢失,kafka 的producer会有重试机制,但重试可能会导致消息的重复。消息重复可以在consumer端处理(幂等性处理)。Kafka 从 0.11.0.0 版本开始引入了幂等和事务这两个特性,在producer到broker这个链路就支持了幂等(exactly once)。

Kafka在0.11.0.0新加的幂等与事务 

官网地址:https://kafka.apache.org/documentation/#upgrade_11_exactly_once_semantics

幂等

引入幂等之前

        在正常情况下,produce向Broker投递消息,broker将消息追加写到对应的流(即某一个topic的某一partition)中,并向Producer返回ACK信号,表示确认收到。

引入幂等性之前

        上图的实现流程是一种理想状态下的消息发送情况,但是实际情况中,会出现各种不确定的因素,比如在Producer在发送给Broker的时候出现网络异常。比如以下这种异常情况的出现: 

        上图这种情况,当Producer第一次发送消息给Broker时,Broker将消息(x2,y2)追加到了消息流中,但是在返回Ack信号给Producer时失败了(比如网络异常) 。此时,Producer端触发重试机制,将消息(x2,y2)重新发送给Broker,Broker接收到消息后,再次将该消息追加到消息流中,然后成功返回Ack信号给Producer。这样下来,消息流中就被重复追加了两条相同的(x2,y2)的消息。 

引入幂等之后

kafka 为实现幂等性,在底层引入了ProducerID和SequenceNumber。

  • ProducerID:在每一个新的Producer初始化时,或被分配一个唯一的ProducerID,这个ProducerID对客户端使用者是不可见的。
  • SequenceNumber:对于每个producerID,Producer发送数据的每个Topic和Partition都对应一个从0开始递增的SequenceNumber值。

数据发送到kafka中会对数据增加Pid 和SequenceId

当ack信号返回Producer时出现网络异常,通信失败情况如下:

        当producer发送消息(x2,y2)给broker 时将其追加到消息流中,此时Broker返回Ack信号给Producer时,发生异常导致Producer接收Ack信号失败。对于Producer来说,会触发重试机制,将消息(x2,y2)再次发送。由于引入了幂等性,在每条消息中附带了PID(ProducerID)和SequenceNumber。相同的PID和SequenceNumber发送给Broker,而之前Broker缓存过之前发送的相同的消息,那么消息流中消息就只有一条(x2,y2)不会出现重复发送的情况。

其处理逻辑为:

        对于收到的每一条消息,只有当它的序列号的值(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 的异常。

幂等的缺陷

单会话有效

        只能实现单会话上的幂等性,不能实现跨会话的幂等性。这里的会话,你可以理解为 Producer 进程的一次运行。当你重启了 Producer 进程之后,这种幂等性保证就丧失了。

        原因:重启之后标识producer的PID就变化了,导致broker无法根据这个<PID,TP,SEQNUM>条件去去判断是否重复。

单分区有效

        只能保证单分区上的幂等性。即一个幂等性 Producer 能够保证某个主题的一个分区上不出现重复消息,它无法实现多个分区的幂等性。

        原因:在某一个partition 上判断是否重复是通过一个递增的sequence number,也就是说这个递增是针对当前特定分区的,如果你要是发送到其他分区上去了,那么递增关系就不存在了。

事务

其他网址

Kafka-事务-解决跨分区跨会话的问题 - KevinT·Mitnick - 博客园
kafka事务 | muggle

简介

        前边说过,Kafka 的 Exactly Once  幂等性只能保证单次会话内的精准一次性,不能解决跨会话和跨分区的问题。

        事务保证Kafka在 Exactly Once  语义的基础上,Producer 和 Consumer 可以跨分区和会话,要么全部成功,要么全部失败。

Producer事务

        为实现跨分区跨会话的事务,需要引入一个全局唯一的  Transaction ID,并将  Producer  获得的 PID  和  Transaction ID 绑定。这样当Producer重启之后,就可以通过正在运行的  Transaction ID 获得原来的  PID。

  为了管理  Transaction,Kafka引入了一个新的组件  Transaction Coordinator。Producer就是通过 Transaction Coordinator 获得  Transaction ID 对应的任务状态。Transaction Coordinator还负责将事务状态写入Kafka的一个内部Topic,这样即使整个服务重启,由于事务状态得到保存,进行中的事务状态可以得到恢复。

Consumer事务

        消费者事务的一致性比较弱,只能够保证消费者消费消息是精准一次的(有且只有一次)。消费者有一个参数 islation.level,这个参数指定的是事务的隔离级别。
它的默认值是 read_uncommitted(未提交读),意思是消费者可以消费生产者未commit的消息。当参数设置为 read_committed,则消费者不能消费到生产者未commit的消息。

事务的使用场景

kafka事务主要是为了保证数据的一致性,现列举如下几个场景供读者参考:

  • producer发的多条消息组成一个事务,这些消息需要对consumer同时可见或者同时不可见;
  • producer可能会给多个topic发送消息,需要保证消息要么全部发送成功要么全部发送失败(操作的原子性);
  • 消费者 消费一个topic,然后做处理再发到另一个topic,这个消费和转发的动作应该在同一事务中;
  • 如果下游消费者只有等上游消息事务提交以后才能读到,当吞吐量大的时候就会有问题,因此有了 read committed和read uncommitted两种事务隔离级别

其他网址

kafka的幂等性和事务性_lianchaozhao的博客-CSDN博客
kafka系列之幂等生产者(11)_【CSDN官方推荐】-CSDN博客
kafka--事务和幂等(二)_atarik@163.com-CSDN博客

以上是关于Kafka--原理--幂等/事务的主要内容,如果未能解决你的问题,请参考以下文章

09 APACHE KAFKA原理

09 APACHE KAFKA原理

kafka消息幂等

Kafka幂等性原理及实现剖析

326面试碰到的kafka问题

kafkaKafka 幂等 Producer