RocketMQ如何保证消息不丢失+消息重复消费问题

一、如何保证消息不丢失

这个问题要从Producer,Consumer和Broker三个方面来回答。

从Producer角度分析,如何确保消息成功发送到了Broker?

        1、可以采用同步发送,即发送一条数据等到接受者返回响应之后再发送下一个数据包。如果返回响应OK,表示消息成功发送到了broker,状态超时或者失败都会触发二次重试。

        2、可以采用分布式事务消息的投递方式

        3、如果一条消息发送之后超时,也可以通过查询日志的API,来检查是否在Broker存储成功。

        总的来说,Producer还是采用同步发送来保证的。

从Broker角度分析,如何确保消息持久化?

        1、消息只要持久化到CommitLog(日志文件)中,即使Broker宕机,未消费的消息也能重新恢复再消费。

        2、Broker的刷盘机制:同步刷盘异步刷盘,不管哪种刷盘都可以保证消息一定存储在pagecache中(内存中),但是同步刷盘更可靠,它是Producer发送消息后等数据持久化到磁盘之后再返回响应给Producer。

        3、Broker支持多Master多Slave同步双写多Master多Slave异步复制模式,消息都是发送给Master主机,但是消费既可以从Master消费,也可以从Slave消费。同步双写模式可以保证即使Master宕机,消息肯定在Slave中有备份,保证了消息不会丢失。

从Consumer角度分析,如何保证消息被成功消费?

        Consumer自身维护了个持久化的offset(对应Message Queue里的min offset),用来标记已经成功消费且已经成功发回Broker的消息下标。如果Consumer消费失败,它会向Broker发回消费失败的状态,发回成功才会更新自己的offset。如果发回给broker时broker挂掉了,Consumer会定时重试,如果Consumer和Broker一起挂掉了,消息还在Broker端存储着,Consumer端的offset也是持久化的,重启之后继续拉取offset之前的消息进行消费。

二、消息重复问题

        RocketMQ并没有对消息重复问题做什么策略处理,需要用户在业务上做幂等。

        消息队列 RocketMQ 消费者在接收到消息以后,有必要根据业务上的唯一 Key 对消息做幂等处理的必要性。

消息幂等的必要性

        在互联网应用中,尤其在网络不稳定的情况下,消息队列 RocketMQ 的消息有可能会出现重复,这个重复简单可以概括为以下情况:

A、发送时消息重复

        当一条消息已被成功发送到服务端并完成持久化,此时出现了网络闪断或者客户端宕机,导致服务端对客户端应答失败。 如果此时生产者意识到消息发送失败并尝试再次发送消息,消费者后续会收到两条内容相同并且 Message ID 也相同的消息。

B、消费时消息重复

        消息消费的场景下,消息已投递到消费者并完成业务处理,当客户端给服务端反馈应答的时候网络闪断。 为了保证消息至少被消费一次,消息队列 RocketMQ 的服务端将在网络恢复后再次尝试投递之前已被处理过的消息,消费者后续会收到两条内容相同并且 Message ID 也相同的消息。

C、负载均衡时消息重复(包括但不限于网络抖动、Broker 重启以及订阅方应用重启)

        当消息队列 RocketMQ 的 Broker 或客户端重启、扩容或缩容时,会触发 Rebalance,此时消费者可能会收到重复消息。

三、消息清理机制

Broker 中的消息被消费后会立即删除吗?

        不会,每条消息都会持久化到 CommitLog 中,每个 Consumer 连接到 Broker 后会维持消费进度信息,当有消息消费后只是当前Consumer 的消费进度(CommitLog 的 offset)更新了。

        当然也可以配置消息被消费后是否立即删除。当消费者成功消费一条消息,并完成确认后,Broker会将这条消息的状态更新为已消费,并根据配置的策略来决定是否立即删除这条消息。

RocketMQ支持两种消息删除策略:

        立即删除:当Broker接到消费者的确认消息时,立刻删除该消息。这种删除策略可以在Broker的配置文件中设置,但是一旦设置为立即删除,就无法保证消息的可靠性。

        延迟删除(默认删除策略):当Broker接到消费者的确认消息时,将该消息的状态标记为"已消费",但并未立即删除,而是将该消息的删除时间延迟到一定的时间之后,再进行删除。这种删除策略可以使消息在删除前保留一段时间,以便于后续的重试或者其他操作。

未消费的消息是否会被删除?

        无论消息是否被消费,RocketMQ的消息保留时间默认为48小时,且不支持修改。RocketMQ消息存储在CommitLog文件中,CommitLog文件大小为1GB,当一个CommitLog文件写满后,会生成一个新的CommitLog文件。RocketMQ删除消息是删除CommitLog文件,而不是删除一条消息。CommitLog文件为顺序写入,当最后写入的一条消息过期时,表示CommitLog文件过期。满足如下任意一个条件,CommitLog文件将会被清理:

  •         每天凌晨4点会清理过期的文件,部分老实例由于未设置时区,清理时间为每天中午12点。
    • 磁盘占中率达到过期清理警戒线70%时,会立刻清理过期的文件。
    • 磁盘占用到达清理警戒线(85%)后,会按照清理规则清理文件,无论是否过期,按照最老的文件开始清理。
    • 磁盘占用达到系统危险警戒线(90%)后,broker会拒绝写入
  • 21
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值