MQ的优势
- 异步调用
- 解耦
- 削峰填谷
MQ的劣势
- 系统的复杂性变高了,加入MQ之后,大家都是异步调用,怎么确保信息有没有丢失,有没有被重复读,消息的顺序性
- 系统的可用性降低了,引入的第三方依赖越来越多,系统的稳定性越差。要是MQ宕机了,系统肯定会造成影响
- 一致性的问题,要是同时向好几个系统发送消息,有的系统成功了,有的系统失败了,如何该保证系统是否一致性
使用MQ要注意的
- 生产者不需要消费者做出反馈。
- 容许短暂的不一致性
- 确实用进去有了效果,用进去带来的收益是大于加入和管理MQ的成本
MQ的工作模式
- Hello world工作模式,一个生产者一个消费者
- work-queues工作模式,一个生产者两个消费者(争夺)
- pub/sub订阅工作模式
- fanout,广播式,给所有绑定交换机的队列发送消息
- routing/direct,定向,给一些符合routing key的队列发送消息
- topic,通配符式,给符合通配符的routing key的队列发送消息(* 一个单词 # 0或者多个单词)
- rpc,远程调用模式
MQ的高级特性
- 消息的可靠投递
在使用MQ,为了保证消息成功发送到出去,MQ提供了两种模式去保证消息的可靠投递。- confirm,确认模式 生产证将消息发送到交换机,不管成功还是失败的话,都有一个确认的回调,收到为true,反之为false
- return,返回模式 当消息发送到交换机发送失败的话,可以有一个返回的回调函数。
利用两个回调可以控制消息的可靠投递
- 消费者确认ack
- 自动确认:acknowledge=“none” 一收到就确认了
- 手动确认:acknowledge=“manual” 要是业务执行成功才确认,要是业务失败,可以broker重新发送
- 根据异常情况确认:acknowledge=“auto”
- 消费者限流
放在消息一下子太多了,导致系统一下子宕机 - TTL(time to live)
当消息到达存活时间后,还没有消费,会被自动清除。可以单个消息或单个队列设置过期时间。一般对队列整体设置过期时间;要是单个消息设置时间了,只有当消息到信息顶端才会被判断时候过期;要是两个都设置了,以时间短的为准 - 死信队列(dead letter exchange)
死信交换机,当消息成为dead message后,可以重新发送到另一个交换机(死信交换机)。- 队列消息长度到达限制
- 消费者拒接消费消息,并且不把消息放回原队列
- 原队列存在消息过期设置,消息超过时间没有被消费
要设置死信交换机、死信队列
- 延迟队列
消息进去队列之后不会立即被消费,只有到达指定时间后,才会被消费
ttl+死信队列实现延迟队列时间
给ttl设置相对应的时间,那些消息到了超时时间就会进入死信队列,进入队列就可以做到相应的业务。 - 消息追踪
要是因为网络等问题导致消息丢失,可以使用第三插件去进行消息追踪。- firehors会将消息发送给amq.rabbit.trace这个系统交换机。(rabbitmqctl trace_on 开启第三插件)
- traceing开启消息日志,慎用,会影响性能
MQ的应用问题
- 消息可靠性保障
消息的补偿机制
- 如图那样,生产者完成自己的业务将结果写入数据库,同时也会发送消息(q1)给消费者,让消费者去执行他自己的业务。
- 如果消费者收到消息,并成功执行完业务就会发送一个消息确认信息给q2,在回调检查服务中监听着q2,收到消息确认信息,就把该消息含的id写入一张数据库表,要是消费者没有收到消息,就没有该操作
- 做一个延迟发送消息,发送给q3,这时候回调检查服务也监听着q3,相同的消息,他会去相应表里面判断是否有该条记录,如果有就说明上述2操作成功,要是没有就会让生产者重新发送消息。
- 要是发送两条信息都失败了,这时候也有一个定时检查服务,定时去检查生产者的数据表和消息数据表是否id一致,要是有偏差,就会让生产者把缺失的数据重新发送
- 消息幂等性保障
幂等性指一次和多次请求某一个资源,得到的结果是一样的。
1.乐观锁机制,可以保障重复发送消息。在执行数据库的sql语句中加入version
2.全局MessageId,将<MessageId,message>存入redis中
MQ的集群
使用HAProxy(负载均衡),实现一种单一进程模型,支持非常大的并发连接数。
MQ是天然支持节点的