kafka的幂等性和事务性

一、综述
在kafka 0.11版本中已经提出,kafka 将对事务和幂等性的支持,使得kafka 端到端exactly once语义成为可能。幂等性与事务性都是Kafka发展过程中非常重要的。
官网摘要
在这里插入图片描述
附录:kafka已经升级到版本
在这里插入图片描述
背景:
向kafka中生产消息时我们一般通过ack确认机制,但不同级别的ACK导致数据有的情况导致丢失,有的情况导致数据重复。所以为了解决生产数据端到端一致性的问题而引入幂等。

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

1、幂等性的实现
kafka 为了实想幂等性,他在底层的设计架构中引入了Producer和SequenceNumber。
(1)、ProducerID:在每一个新的Producer初始化时,或被分配一个唯一的ProducerID,这个ProducerID对客户端使用者是不可见的。
(2)、sequenceNumber:对于每个producerID,Producer发送数据的每个Topic和Partition都对饮一个从0开始递增的SequenceNumber值

2、引入幂等性之前
在这里插入图片描述
上图的实现流程是一种理想状态下的消息发送情况,但是实际情况中,会出现各种不确定的因素,比如在Producer在发送给Broker的时候出现网络异常。比如以下这种异常情况的出现:
在这里插入图片描述
上图这种情况,当Producer第一次发送消息给Broker时,Broker将消息(x2,y2)追加到了消息流中,但是在返回Ack信号给Producer时失败了(比如网络异常) 。此时,Producer端触发重试机制,将消息(x2,y2)重新发送给Broker,Broker接收到消息后,再次将该消息追加到消息流中,然后成功返回Ack信号给Producer。这样下来,消息流中就被重复追加了两条相同的(x2,y2)的消息。

3、当引入幂等性后解决的问题。
同样的数据发送到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)不会出现重复发送的情况。

相关源码分析 TODO :https://www.cnblogs.com/smartloli/p/11922639.html

三、事务
在数据端对端数据保证中,另个一个我们特别关注的问题就是事务。即原子性操作。对应的结果是同时成功或者同时失败,kafka的事务注重的生产和消费的的原子性操作。典型的例子为。
一系列的Producer生产消息和消费消息提交Offsets的操作在一个事务中
例如产生的场景包括
(1)、producer多次发送消息封装在一个原子性操作,即要求同时成功,或者同时失败。
(2)、在消费者&生产者的模式下,因为consumer在 commit offsets出现问题时,导致重复消费消息时,需要将这个模式下的Consumer和Commit offsets操作和Producer一系列生产消息的操作封装成一个原子性操作。
(3)、kafka的事务总体可以分为三方面的内容,1)、只有Producer生产消息,这种场景需要事务的介入;
2)、消费消息和生产消息并存,比如Consumer&Producer模式,这种场景是一般Kafka项目中比较常见的模式,需要事务介入;3)、但是只有Consumer消费消息,这种操作在实际项目中意义不大,和手动Commit Offsets的结果一样,而且这种场景不是事务的引入目的。

注意:容易产生重复消费问题Balance
如,在Consumer中Commit Offsets时,当Consumer在消费完成时Commit的Offsets为100(假设最近一次Commit的Offsets为50),那么执行触发Balance时,其他Consumer就会重复消费消息(消费的Offsets介于50~100之间的消息)。
2、事务可以提供可用的API
producer提供了五种事务方法,他们分别时:initTransactions()、beginTransaction()、sendOffsetsToTransaction()、commitTransaction()、abortTransaction(),代码定义在

org.apache.kafka.clients.producer.Producer<K,V>接口中,
复制代码
// 初始化事务,需要注意确保transation.id属性被分配
void initTransactions();
// 开启事务
void beginTransaction() throws ProducerFencedException;
// 为Consumer提供的在事务内Commit Offsets的操作
void sendOffsetsToTransaction(Map<TopicPartition, OffsetAndMetadata> offsets,
                              String consumerGroupId) throws ProducerFencedException;
// 提交事务
void commitTransaction() throws ProducerFencedException;
// 放弃事务,类似于回滚事务的操作
void abortTransaction() throws ProducerFencedException;

综上:kafka的幂等性和事务时比较重要的特性,特别在数据丢失和重复的问题上非常重要,kafka引入幂等性,实际的原理也比较好了解,而事务与数据库的事务类似,有数据库使用的经验对理解Kafka的事务也比较容易接受。

猜你喜欢

转载自blog.csdn.net/weixin_40809627/article/details/106918385
今日推荐