kafka保证消息不丢失 / exactly once / rocketmq事务消息

本文详细介绍了Kafka如何确保消息不丢失,包括Producer的配置、Consumer的手动提交、副本机制以及At-most-once、At-least-once和Exactly-once三种消息传递语义。通过设置合适的配置参数和使用幂等Producer、事务性消息,可以实现不同程度的消息可靠性。RocketMQ的事务消息处理也被提及,提供了一种确保消息准确性的方案。
摘要由CSDN通过智能技术生成

kafka如何保证消息不丢失

消息丢失的场景

  1. producer: config.Producer.RequiredAcks + 异步发送模式

    1. producer把消息发送给broker,因为网络抖动,消息没有到达broker-master
    2. producer把消息发送给broker-master,master接收到消息,在未将消息同步给follower之前,挂掉了
      1. 上面2个问题,都可以通过设置ACK来保证消息不丢失,即 config.Producer.RequiredAcks = sarama.WaitForAll
      2. 采用”异步发送模式“,当发送失败时,重新发送
  2. consumer成功拉取到了消息,consumer未处理完业务逻辑,就挂了,导致消息没被正确的处理 ==>(手动提交):offset未提交的消息,被认为未被消费

    1. Consumer.Offsets.AutoCommit.Enable = false // 禁用自动提交,改为手动提交
    2. 在处理完业务逻辑之后,调用sess.MarkMessage(msg, “”),手动提交
  3. broker

    1. Kafka 为分区(Partition)引入了多副本(Replica)机制。分区(Partition)中的多个副本之间会有一个叫做 leader 的家伙,其他副本称为 follower。我们发送的消息会被发送到 leader 副本,然后 follower 副本才能从 leader 副本中拉取消息进行同步。生产者和消费者只与 leader 副本交互。可以理解为其他副本只是 leader 副本的拷贝,它们的存在只是为了保证消息存储的安全性

    2. 试想一种情况:假如 leader 副本所在的 broker 突然挂掉,那么就要从 follower 副本重新选出一个 leader ,但是 leader 的数据还有一些没有被 follower 副本的同步的话,就会造成消息丢失(通过配置可以避免该问题)

// 每个分区(partition) 至少有3个副本
replication.factor >= 3
// 代表消息至少要被写入到2个副本才算是被成功发送
min.insync.replicas > 1
// 非ISR中的副本不能够参与选举
unclean.leader.election.enable = false

kafka的3种方式

At-most-once(最多一次):如果在ack超时或返回错误时,生产者没有重试,那么消息可能最终不会被写入Kafka topic,因此不会传递给消费者。(不存在消息重复,但是会丢失消息)

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

At-least-once(最少一次)

        1. 如果生产者从Kafka broker接收到一个确认(ack)并且ack = all,这意味着消息已经被写入Kafka topic一次。

        2. 然而,如果生产者ack超时或收到一个错误,它可能会重试发送消息:如果broker在它发送ack之前失败,但消息已经被成功写入Kafka topic后,此重试将导致消息被写入两次,因此将不止一次地传递给最终消费者

Exactly-once(精确一次):消息既不会丢失,也不会重复

如何实现exactly once 

        kafka通过幂等性和事务,实现exactly once。

1. 幂等producer

    1. 当Producer发送消息(x2,y2)给Broker时

        2. Broker接收到消息并将其追加到消息流中。

        3. 此时,Broker返回Ack信号给Producer时,发生异常导致Producer接收Ack信号失败。

        4. 对于Producer来说,会触发重试机制,将消息(x2,y2)再次发送,但是,由于引入了幂等性,在每条消息中附带了PID(ProducerID)和SequenceNumber。相同的PID和SequenceNumber发送给Broker,而之前Broker缓存过之前发送的相同的消息,那么在消息流中的消息就只有一条(x2,y2),不会出现重复发送的情况;

局限性:实现比较简单,同样的限制也比较大,存在下面的弊端(无法保证多分区多会话的幂等性)

          

    1.只能保证 Producer 在单个会话内不丟不重:如果 Producer 出现意外挂掉再重启是无法保证的(幂等性情况下,是无法获取之前的状态信息,因此是无法做到跨会话级别的不丢不重)

        2.幂等性不能跨多个 Topic-Partition,只能保证单个 partition 内的幂等性:当涉及多个 Topic-Partition 时,这中间的状态并没有同步

==> 如果需要跨会话、跨多个 topic-partition 的情况,需要使用 Kafka 的事务性来实现

2. 事务性

先看一个2PC用例图

        

kafka事务消息处理_Ivan-Zhong的博客-CSDN博客_kafka事务消息

Rocketmq事务消息

   监听器(在发送方中定义)需要实现TransactionListener,有两个功能:① prepare消息发送成功,则在executeLocalTransaction()中执行本地事务;② 在checkLocalTransaction()中执行本地事务状态回查逻辑。

 发送事务消息可能存在3种情况:

1)正常情况:步骤1 -> 步骤2 -> 步骤3 -> 步骤4

  发送方先发送prepare消息,发送成功后执行本地事务,本地事务的执行成功通知RocketMQ服务器进行commit投递消息,本地事务执行失败通知RocketMQ服务器rollback删除消息不进行投递。

2)回查情况:步骤1 -> 步骤2 -> 步骤3 -> 步骤5 -> 步骤6 -> 步骤7

  发送方发送prepare消息,发送成功后执行本地事务,但由于本地事务可能执行时间较长,如果超过一定时间RocketMQ服务器没有收到处理结果,不知道是commit还是rollback,这时会根据定时任务进行发送方本地事务状态的回查,在监听器中进行事务状态回查,如果查到本地事务处理结果,则返回commit或rollback状态;如果还是未查到本地事务处理结果,返回unknow状态,RocketMQ服务器不会做操作仍会进行定时回查

3)异常情况:步骤1 -> 步骤2 -> 步骤3 -> 步骤5 -> 步骤6 -> 人工干预队列

  基于情况2的情况,如果回查次数达到上限,将消息放入人工干预队列

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值