首先是为什么使用消息队列
消息队列优点 : 异步 、解耦 、削峰
消息队列的选择
消息队列消息的分发方式
1、Round_Robin 轮询法
2、平均法
MQ的缺点 :
1、系统可用性降低
在系统中 A 通过消息队列调用C,MQ挂掉了
应该考虑MQ高可用性
万一MQ挂掉导致系统崩溃;RabbitMQ 有三种模式 : 单机、普通集群、镜像集群
- 单机就是一个MQ在跑
- 普通就是多个MQ在跑,每一个MQ都是复制过去的、一样的;多台机子上启动多个MQ实例
- 镜像集群模式就是你创建的Queen无论是数据元还是消息数据都存在多个实例当中,每次写消息到queue的时候,都会吧消息自动到多个queue中消息同步
坏处就是性能消耗太大、扩展性低:就算是新增queue还是复制的所有的消息
2、 数据一致:数据的幂等性
幂等性 :多次操作保证数据不改变,就是说多次操作,结果还是跟一次操作的时候一样;
数据一致性根据业务处理来操作:
1、消费者方面携带一个业务id查询数据库,拿唯一键查询数据库,不存在直接写,存在就更新或者丢弃消息
2、生产者方面,对每一条消息生成一个消息ID,控制消息的重复投递;
3、拿redis做消费记录,查看记录是否消费过
3、数据丢失
数据丢失可能会出现在生产者、MQ、消费者
生产者丢失消息
生产者把消息发送给MQ的时候因为一些原因消息丢失了
1、使用RabbitMQ提供的事物:在发送之前开启,如果消息没有被MQ收到,那么生产者就会报错,事物就会回滚,然后重试发送消息;RabbitMQ事物机制是同步,但是会出现同步阻塞操作,等待是否成功,太耗性能造成吞吐量下降
2、开启confirm模式,生产者部分开启confirm模式之后,每次写消息都会分配唯一id,rabbitMq会回传ack消息告诉你消息成功了,如果没有处理这个消息,会返回你nack,告诉你消息失败了,超过一定时间没有收到消息回调,可以进行重发
二者不同:事物是同步的,提交一个事物之后就会阻塞;confirm是异步的,一般都是使用confirm;
消费者丢失
钢消费到,还没处理,结果挂掉了,MQ认为消费了,所以数据丢失;
使用Ack机制,关闭MQ自动ack,通过api调用ack,确保处理完之后调用ack,如果没有处理完那么就没有ack,MQ就认为你没有处理完,MQ会把这个消息发送给其他的comsumer。
rabbitmq自己弄丢了数据
开启MQ持久化,消息写入之后持久化到磁盘上
1、创建queue的时候就持久化
2、消息设置为持久化
注意,哪怕是你给 RabbitMQ 开启了持久化机制,也有一种可能,就是这个消息写到了 RabbitMQ 中,但是还没来得及持久化到磁盘上,结果不巧,此时 RabbitMQ 挂了,就会导致内存里的一点点数据丢失。
所以,持久化可以跟生产者那边的 confirm
机制配合起来,只有消息被持久化到磁盘之后,才会通知生产者 ack
了,所以哪怕是在持久化到磁盘之前,RabbitMQ 挂了,数据丢了,生产者收不到 ack
,你也是可以自己重发的。
MQ崩溃数据不丢失
消息持久化:消息的queue持久化
channel.queueDeclare(
"warehouse_schedule_delivery",
true,
false,
false,
null);
大家看到上面那行定义和创建queue的代码么?核心在于第二个参数,第二个参数是true。
MQ吧queue相关的消息持久化到磁盘上,重启之后可以恢复持久化queue
Message持久化
消息堆积
1、大量消息堆积在MQ中
- 先修复consumer问题,保证恢复消费速度,然后停掉consumer
- 临时建立10呗的queue
- 临时分发堆积的消息到queue中,全部消费掉,消费完之后对接回原来的consumer
2、消息过期丢失
重新导入消费
3、积压长时间没有处理,mq放不下
先丢弃然后在重复消费