05 | 如何保证消息不丢失

对大部分业务系统来说,丢消息意味着数据丢失,是不可接受的。丢消息也成为大部分用消息队列的同学最头痛的问题。

目前主流消息队列产品都提供了完善的消息可靠性机制,保证消息的不丢。

检测消息丢失的方法

丢消息还不知道,是用消息队列的最尴尬情况。一般而言,新系统刚上线,各方面不稳定,需要磨合期,这个时候特别要监控系统中是否有消息丢失的情况。

IT基础设施较完善的公司,都有分布式的链路追踪系统,使用类似追踪系统可以很方便地追踪每条消息。而没有,则可以利用消息的有序性进行验证。

在Producer端,给每个发出的消息附加一个连续递增的序号,然后在consumer端检查这个序号的连续性。

若没有消息丢失,Consumer 收到消息的序号必然是连续递增,或者收到消息,其序号必然是上一条消息的序号+1。如果检测到序号不连续,那就是丢消息了。

大多数消息队列的客户端都支持拦截器机制,可以利用这个拦截器机制,在producer发消息之前的拦截器中将序号注入到消息中,在consumer收到消息的拦截器中检测序号的连续性,这样实现的好处是消息检测的代码不会侵入业务,待系统稳定后,也方便将这部分检测的逻辑关闭或删除。

如果是在一个分布式系统中实现这个检测方法,有几个问题需要注意。

Topic内只能保证分区内有序。因此必须发指定分区的消息,在单分区上检测丢失。

对于Producer多实例,不好协调发送顺序。因此由每个Producer分别生成各自序号,附加上Producer的标识,Consumer端分Producer进行序号有序检测。

对于Consumer多实例,最好保证一个分区被一个consumer检测消息序号的连续性有序性。数量最好和分区数量一致,做到consumer和分区一一对应??

确保消息可靠传递

检测消息丢失不能解决消息丢失。

确保消息的可靠传递,需要找到消息会发生丢失的环节,并找到策略去避免。

首先明确一条消息从产生到被消费的过程

     

             |   生产阶段  | 存储阶段 |   消费阶段   |

Producer  —Send—>  Broker     —Pull—>  Consumer

                <—Ack——                   <—Ack—

  • 生产阶段:消息从Producer通过网络发送到Broker端
  • 存储阶段:消息在Broker端存储,若是集群,消息会在这个阶段被复制到其它的副本上
  • 消费阶段:Consumer从Broker上拉取消息,通过网络传输发送到Consumer上

1. 生产阶段:网络传输导致丢数据。请求-确认机制确保。有些消息队列在一段时间没收到确认会自动重试,重试再不行会抛出异常, 此时业务代码需要重试发送,若使用异步发送则需要在异步回调中捕获异常重试。

2. 存储阶段:Broker宕机导致丢数据。单节点配置写入磁盘后再发送确认,RMQ需要配置同步刷盘。磁盘的损坏导致丢数据。集群多节点配置至少写入两个节点后返回确认

3. 消费阶段:请求-确认机制确保。消费逻辑结束后返回确认。

小结

一条消息从发送到消费的整个流程中,消息队列如何确保可靠性。分为三个阶段,生产,存储,消费。

生产阶段,需要捕获发送错误,并重发消息。

存储阶段,需要配置刷盘和复制相关的参数,让消息写到多个副本的磁盘上,确保不因为某个broker宕机或者磁盘损坏而丢失。

消费阶段,需要处理完业务逻辑再确认。

思考

Broker和Consumer都会收到重复的消息,如何避免重复消费带来的问题?

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值