rabbitmq的常见问题及解决方案 lq

rabbitmq的常见问题及解决方案:https://hollis.blog.csdn.net/article/details/107678977
  1. 消息丢失:消息确认模式+持久化(消息可靠性提升,可能会导致性能下降,比如消息刷盘,多副本同步。)
    • 生产消息:生产者把消息发送到broker,要处理broker传回来的响应,不论是同步还是异步发送消息,都得做好捕获异常,处理好响应,如果Broker返回写入失败等错误消息,需要重试发送。当多次发送失败需要作报警,日志记录等。这样就能保证在生产消息阶段消息不会丢失。
    • 存储消息:消息要持久化,一台服务器需要在消息刷盘后再给生产者响应;集群部署,有多副本机制,即消息不仅仅要写入当前Broker,还需要写入副本机中。那配置成至少写入两台机子后再给生产者响应。这样基本上就能保证存储的可靠了。
    • 消费消息:消费者真正执行完业务逻辑之后,再发送给Broker消费成功,这才是真正的消费了。所以只要我们在消息业务逻辑处理完成之后再给Broker响应,那么消费阶段消息就不会丢失。
      1. 消息持久化:
        • exchange:durable=True
        • queue:durable=True
        • message:BasicProperties(delivery_mode=2) 2是持久化,1是不持久化
      2. 发送确认
      3. 手动消费确认
        • ack:消费成功
        • nack:消费失败
  2. 重复消息:保证幂等性:
    • 先从数据库层面来看,修改数据的操作,那加个乐观锁就行了,(每次修改前先查询出version,修改的条件判断version是否跟查询出的version一致)
    • 如果是针对订单,可以建立一个全局唯一索引,每次操作都进日志表,然后操作前去日志表查是否操作过这个唯一索引,如果操作过那么日志表里肯定有这个数据
    • 再从aop层面看,可以用分布式锁的概念,如果有唯一索引的话可以把唯一索引作为key加到redis里做校验,如果没有的话可以用构造一个唯一的数据,userid+操作数据uuid拼接作为key
  3. 处理消息堆积:具体情况具体分析:消费能力弱---优化消费逻辑,批量处理消息 增加topic队列和消费者数量,队列一定要增加
  4. 消息百分百成功投递
    image
    1. Step 1:首先把消息信息(业务数据)存储到数据库中,紧接着,我们再把这个消息记录也存储到一张消息记录表里(或者另外一个同源数据库的消息记录表)
    2. Step 2:发送消息到MQ Broker节点(采用confirm方式发送,会有异步的返回结果)
    3. Step 3、4:生产者端接受MQ Broker节点返回的Confirm确认消息结果,然后进行更新消息记录表里的消息状态。比如默认Status = 0 当收到消息确认成功后,更新为1即可!
    4. Step 5:但是在消息确认这个过程中可能由于网络闪断、MQ Broker端异常等原因导致 回送消息失败或者异常。这个时候就需要发送方(生产者)对消息进行可靠性投递了,保障消息不丢失,100%的投递成功!(有一种极限情况是闪断,Broker返回的成功确认消息,但是生产端由于网络闪断没收到,这个时候重新投递可能会造成消息重复,需要消费端去做幂等处理)所以我们需要有一个定时任务,(比如每5分钟拉取一下处于中间状态的消息,当然这个消息可以设置一个超时时间,比如超过1分钟 Status = 0 ,也就说明了1分钟这个时间窗口内,我们的消息没有被确认,那么会被定时任务拉取出来)
    5. Step 6:接下来我们把中间状态的消息进行重新投递 retry send,继续发送消息到MQ ,当然也可能有多种原因导致发送失败
    6. Step 7:我们可以采用设置最大努力尝试次数,比如投递了3次,还是失败,那么我们可以将最终状态设置为Status = 2 ,最后 交由人工解决处理此类问题(或者把消息转储到失败表中)。
    • 数据库文件
      -- ----------------------------
      -- Table structure for broker_message_log
      -- ----------------------------
      DROP TABLE IF EXISTS `broker_message_log`;
      CREATE TABLE `broker_message_log` (
        `message_id` varchar(255) NOT NULL COMMENT '消息唯一ID',
        `message` varchar(4000) NOT NULL COMMENT '消息内容',
        `try_count` int(4) DEFAULT '0' COMMENT '重试次数',
        `status` varchar(10) DEFAULT '' COMMENT '消息投递状态 0投递中,1投递成功,2投递失败',
        `next_retry` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP COMMENT '下一次重试时间',
        `create_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
        `update_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
        PRIMARY KEY (`message_id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
      
      -- ----------------------------
      -- Table structure for t_order
      -- ----------------------------
      DROP TABLE IF EXISTS `t_order`;
      CREATE TABLE `t_order` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `name` varchar(255) DEFAULT NULL,
        `message_id` varchar(255) DEFAULT NULL,
        PRIMARY KEY (`id`)
      ) ENGINE=InnoDB AUTO_INCREMENT=2018091102 DEFAULT CHARSET=utf8;
      
原文地址:https://www.cnblogs.com/rbwbear/p/15557827.html