主要用来做异步、削峰、解耦

rabbitmq延时队列

可以设置队列延时,也可以设置消息延时

  • 生产者->延时队列交换机->延时队列->死信队列->死信队列交换机->消费者
  • 如果是不同梯度的延时并且梯度很少,例如 5s, 10s, 30s只有3个,可以设置不同的队列和交换机

rabbitMQ python消费消息 取内容 rabbitmq去重消息队列_重发

  • 中间的坑

rabbitMQ python消费消息 取内容 rabbitmq去重消息队列_rabbitmq_02

重复消费

解决方法:
造成重复消费有可能是生产段发多了或者消费段方法没有做幂等导致超收了。
生产段:在发送前可以为每个消息设置一个唯一id作为幂等判断的条件,如果有重复的去重后发送
消费段:接收段可以根据bizid(业务id),例如业务id或流水id来去判断之前有没有,有的话就直接返回

顺序消费

解决方法:
造成原因可能是对于同一id本来是按照队列顺序发送,例如队列消费理论上是:增->改->删,结果因为当时数据量大,同步也多,结果到消费段顺序成了:删->增->改

rabbitMQ python消费消息 取内容 rabbitmq去重消息队列_rabbitmq_03

可以多建立几个队列,然后对一类业务提取一个唯一业务号,对业务号Hash取模,让同一类业务走同一个队列

消息丢失

rabbitMQ python消费消息 取内容 rabbitmq去重消息队列_消息队列_04

解决方法:

1. 生产者段消息丢失,可能是因为网络波动
① 手动mq事务
1. 手动开启rabbitmq事务(channel.txSelect)
2. 发送消息
3. 如果消息没有被rabbitmq接收到,生产段发生异常,就回滚(channel.txRollback),然后重发消息,否则如果成功就手动提交事务(channel.txCommit)
② Confirm机制
1. 生产段发送消息时可以开启confirm机制,需要传输一个唯一id过去;
2. 如果rabbitmq段成功接收会回调handleAck方法,并将这个唯一id传回来告诉生产者这个id已经接收成功了,如果接收失败了会回调handleNack方法,并将id传回告诉生产者这个id接收失败了,后面可以选择是否重发

rabbitMQ python消费消息 取内容 rabbitmq去重消息队列_重发_05

手动mq事务是同步的,比价占用当前时间的,所以一般选择异步的Confirm机制

2. rabbitmq段消息丢失,可能是收到了生产者的消息,但是还未发送到消费段,也未持久到磁盘上或内存,mq发生了宕机

解决方法:
①必须同时设置队列为持久化和发送消息时,消息设置为持久化,这样就算mq发送了宕机,重启后会重新从磁盘上读数据

3. 消费者段接收了消息,但是还未消费完,结果系统挂了,走了异常默认是已经消费完了

解决方法:
①如果进入异常了就重发一次,如果mq中的消费方法是很多业务模块的,需要保证幂等性,例如消费方法中有:保存数据模块,结算模块, 发送邮件模块,调用第三方接口模块,如果在结算模块失败了,其实保存数据模块已经执行了一次,如果再执行一次就会重复,所以在每个模块中需要做一个前置判断,判断之前是否之前执行过这条数据,如果执行过了就直接返回。
②设置多个消费者,如果有较大概率锁表,可以设置排它消费,每次只能是其中一个消费,如果另外一个挂了,可以用备用的消费。

因为①方法不一定能保证系统宕机能重发成功,所以一般用①和②结合使用

 

消息堆积

消息堆积一般有两种情况,一个是生产段生产的太快了,另外一个是消费段消费的太慢了。
生产段生产太快解决:
可以优化下生产代码,减少发送频率,例如对于批量队列,某段时间内产生重复的队列消息就要做下去重处理

消费段消费太慢解决:
可以另外部署几台下消费服务应用,例如有一次生产线上有一个队列大批量消息堆积了,导致队列最后都不消费了,当时生产环境又不能停,所以就另外部署了几台消费服务应用去消费掉了,等待使用低峰的时候再去把生产太快的地方给优化下,降低发送频率