[问题记录]解决RabbitMQ消息丢失与重复消费问题

13816人阅读 评论(0) 收藏 举报
分类:

本文仅记录排查和问题定位、解决的过程。


1. 背景

最近用户反馈提交的SQL查询一直处于长时间等待状态,经过排查观察,发现部分查询请求丢失,导致用户提交的查询未被正常接收,继而长时间无响应。

现象:集市SQL控制台提交10个简单SQL查询 -> 消息发送方:发送10条消息至消息队列 -> 消息消费方:只消费了7条消息

2. 现状

2.1. 当前SQL查询的整体流程

1

  • 生产者:PHP
    • 将用户的SQL查询记录在DB表,标识查询任务状态(f_status)为运行中;
    • 将DB表中的任务id、提交人等信息发送到RabbitMQ;
  • 消息队列:RabbitMQ
    • PHP消息提交到了交换机;
    • 交换机再把消息分发给指定的消息队列;
  • 消费者:Python
    • 主进程监听消息队列,一旦有消息就不停拉取;
    • 拉取一条消息,就从进程池调起一个空闲进程来处理消息;
    • 随后反馈ACK给消息队列,将消息从消息队列中移除;

2.2. 消息发送方:Web端

结论:消息发送正常
排查步骤:查看log

2.3. 消息队列

结论:消息数量正常
诊断步骤:
执行机安装rabbitmq-dump-queue插件,用于dump队列的消息;
1. 执行机:停止服务;
2. 用户:提交10个SQL查询:
3. 发送方:查看Web服务端的输出日志,确定10个消息已经往消息队列写;
4. 执行机:通过rabbitmq-dump-queue查看队列的消息,确认是正常10个消息写入;

watch -n 1 '$GOPATH/src/rabbitmq-dump-queue/rabbitmq-dump-queue -uri="amqp://guest:guest@xxxxx:5672" -queue ph_open_task'

3
5. 执行机:启动服务,消息队列中的消息全部被接收;

2.4. 消息接收方

代码逻辑:

try:
    pool = Pool(processes=40)

    def callback(ch, method, properties, body):
        try:
            doSomething...
            pool.apply_async(process)
        except Exception as e:
            print traceback.format_exc()
            logger_msg.info(traceback.format_exc())
        finally:
            // 这里会有问题,即使消息未被处理也会反馈ACK给RabbitMQ
            ch.basic_ack(delivery_tag=method.delivery_tag)

    while True:
        try:
            connection = pika.BlockingConnection(
                pika.ConnectionParameters(host='xxxxxxxx'))
            channel = connection.channel()
            channel.queue_declare(queue=queue_name, durable=True)
            channel.basic_qos(prefetch_count=1)
            channel.basic_consume(callback, queue=queue_name, no_ack=False)
            channel.start_consuming()
        except pika.exceptions.ConnectionClosed as e:
            continue
except Exception as e:
    logger_msg.info(traceback.format_exc())
finally:
    channel.basic_ack(delivery_tag=method.delivery_tag)

    pool.close()
    pool.join()

结论:本例中消费者主进程将持续监听MQ,一旦MQ有消息将会拉取,随后从进程池中启动子进程来处理消息,但是从进程池启动子进程的过程并不一定成功(若当前进程池没有空闲子进程),而主进程不管任何情况下都给MQ发送ACK状态码,从而MQ将未处理的消息移除掉,导致消息丢失

3. 方案

问题是在消费者环节产生,因此对消费者做改动,需要调整消费者的架构:
* 原来逻辑:使用进程池技术,主进程负责监听、接收MQ的消息,子进程负责执行MQ的消息,缺点是单一的主进程无法简单处理ACK状态码,不易维护;
* 现有逻辑:使用RabbitMQ自身特性(work_queue),消费者不再维护进程池,是单进程,负责监听、接收、处理MQ的消息,处理完了以后再反馈ACK状态码,进程与进程之间互不干扰,易维护,并发量大时可随时增加消费者进程;

目前方案的问题以及解决方案:

  • 问题1:消息重复消费
    描述:用户在页面停止查询时,会导致消费者进程被杀死,因此ACK状态码未反馈至MQ,从而消息一直存留在MQ中,当新的消费者启动时会重新消费;
    解决方案:消费者每次执行查询前,首先在DB上查询任务的执行状态,若处于「取消/失败/成功」则表示已经由其它消费者消费过,那么直接返回ACK状态码给MQ,将消息从MQ中移除;

  • 问题2:进程池如何维护?
    描述:用户在页面停止查询时,会导致消费者进程被杀死,导致消费者数量减少;
    解决方案:维护一个监控脚本,每分钟轮询消费者进程数,若少于40个进程,则新启动一个消费者,直到数量足够;

4

查看评论

RabbitMQ延迟消费和重复消费

使用RabbitMQ实现延迟任务场景一:物联网系统经常会遇到向终端下发命令,如果命令一段时间没有应答,就需要设置成超时。场景二:订单下单之后30分钟后,如果用户没有付钱,则系统自动取消订单。延迟任务的...
  • quliuwuyiz
  • quliuwuyiz
  • 2018-02-09 18:17:35
  • 454

解决rabbitmq消息队列的顺序及重复消费问题

五一期间去韩国游玩,顺便去了朋友公司扯淡去了。 所谓的扯淡,就是过去听技术分享,有python, golang, devops,docker一些话题。总的来说,技术方面跟国内还是有一些差距的。  ...
  • varyall
  • varyall
  • 2018-01-20 00:03:31
  • 1022

解决RabbitMQ消息丢失与重复消费问题

原文地址:http://blog.csdn.net/yeweiouyang/article/details/74943278本文仅记录排查和问题定位、解决的过程。1. 背景最近用户反馈提交的SQL查询...
  • tanga842428
  • tanga842428
  • 2018-03-14 10:21:29
  • 160

RabbitMq六种使用模式(2)_多个消费者

RabbitMq六种使用模式(2)
  • zhangbinalan
  • zhangbinalan
  • 2014-07-14 18:38:17
  • 15520

Spring-Rabbit消费多个mq中相同的队列

因为业务规模比较大,采用多台rabbitmq服务器进行处理,在每台rabbitmq建立相同的exchange,采用客户端分片的方式,生产者根据hash分发消息到不同的服务器中。 作为消费者,必须能支...
  • xinluke
  • xinluke
  • 2017-01-11 20:40:11
  • 2018

rabbitmq消费消息的两种方式

rabbitMQ中consumer通过建立到queue的连接,创建channel对象,通过channel通道获取message,Consumer可以声明式的以API轮询poll的方式主动从queue的...
  • liyantianmin
  • liyantianmin
  • 2015-06-30 15:06:50
  • 13906

java 实现利用 RabbitMQ 发送和消费消息

java 实现利用 RabbitMQ 发送和消费消息
  • wang_dong_yang
  • wang_dong_yang
  • 2015-11-10 14:38:01
  • 5959

rabbitMQ学习笔记(三) 消息确认与公平调度消费者

从本节开始称Sender为生产者 , Recv为消费者 一、消息确认 为了确保消息一定被消费者处理,rabbitMQ提供了消息确认功能,就是在消费者处理完任务之后,就给服务器一个回馈,服务器就会将该...
  • is_zhoufeng
  • is_zhoufeng
  • 2013-08-17 16:52:57
  • 23082

Rabbitmq消费失败死信队列

Rabbitmq 重消费处理一 处理流程图: 业务交换机:正常接收发送者,发送过来的消息,交换机类型topicAE交换机: 当业务交换机无法根据指定的routingkey去路由到队列的时候,会全...
  • qq_29778131
  • qq_29778131
  • 2016-09-14 12:26:34
  • 8596

rabbitmq 重复ACK导致消息丢失

rabbitmq 重复ACK导致消息丢失 太重要了所以转载,作为私用,希望原作者不要怪我 rabbitmq 重复确认导致消息丢失 背景 rabbitmq 在应用场景中,大多...
  • yangchangyong0
  • yangchangyong0
  • 2017-03-28 15:31:46
  • 498
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 45万+
    积分: 6174
    排名: 5026
    第三方账号
    博客专栏