常用消息队列框架与技术选型( 三 )

  • MQ:假设网络出现了波动,消费者消费完一条消息后,发送ack时,MQ还没来得及接受 , 突然挂了,导致MQ以为消费者还未消费该条消息,MQ回复后会再次推送了这条消息 , 导致出现重复消费 。
  • 消费者:消费者接收到消息后,正准备发送ack到MQ,突然消费者挂了,还没得及发送ack,这时MQ以为消费者还没消费该消息,消费者重启后,MQ再次推送该条消息 。
  • 如何解决呢?在正常情况下 , 生产者是客户,我们很难避免出现用户重复点击的情况 , 而MQ是允许存在多条一样的消息,但消费者是不允许出现消费两条一样的数据,所以幂等性一般是在消费端实现的:
    • 状态判断:消费者把消费消息记录到redis中,再次消费时先到redis判断是否存在该数据,存在则表示消费过 , 直接丢弃
    • 业务判断:消费完数据后 , 都是需要插入到数据库中,使用数据库的唯一约束防止重复消费 。插入数据库前先查询是否存在该数据 , 存在则直接丢弃消息,这种方式是比较简单粗暴地解决问题
    如何解决消息丢失?消息丢失属于比较常见的问题 。一般有生产端丢失、MQ服务丢失、消费端丢失等三种情况 。针对各种情况应对方式也不一样 。
    生产端丢失的解决方案主要有 。
    • 开启confirm模式,生产着收到MQ发回的confirm确认之后,再进行消息删除,否则消息重推 。
    • 生产者端消息保存的数据库,由后台定时程序异步推送 , 收到confirm确认则认为成功,否则消息重推,重推多次均未成功 , 则认为发送失败 。
    MQ服务丢失则主要是开启消息持久化 , 让消息及时保存到磁盘 。
    消费端消息丢失则关闭自动ack确认,消息消费成功后手动发送ack确认 。消息消费失败,则重新消费 。
    (3)如何保证消息有序性在生产端发布消息时,每次法发布消息都把上一条消息的ID记录到消息体中,消费者接收到消息时,做如下操作:
    • 先根据上一条Id去检查是否存在上一条消息还没被消费,如果不存在(消费后去掉id),则正常进行,如果正常操作
    • 如果存在,则根据id到数据库检查是否被消费,如果被消费,则正常操作
    • 如果还没被消费,则休眠一定时间(比如30ms),再重新检查,如被消费,则正常操作
    • 如果还没被消费 , 则抛出异常
    (4) 如何解决消息积压问题?所谓的消息积压,即生成者生成消息太快,而消费者处理消息太慢,从而导致消费端消息积压在MQ中无法处理的问题 。遇到这种消息积压的情况,可以根据消息重要程度,分为两种情况处理:
    • 如果消息可以被丢弃,那么直接丢弃就好了
    • 一般情况下,消息是不可以被丢弃的 , 这样就需要考虑策略了,可以将原本的消费端重新部署为一个新的消息队列(MQ)实例,并在后续增加消费端,以形成另一条生产-消息-消费的线路 。

    常用消息队列框架与技术选型

    文章插图
    PS:实际项目中是否需要使用消息队列以及如何使用,还是要根据业务特点进行选择 , 一个UV没几个的系统,使用消息队列,则纯粹是老板掏钱、研发受罪了 。




    推荐阅读