本文共 2074 字,大约阅读时间需要 6 分钟。
0、消息中间件的作用
(1)解耦
(2)冗余(消息冗余存储)
(3)扩展性
(4)削峰
(4)可恢复性
(5)缓冲
(6)异步
(7)顺序保证(RabbitMQ不支持)
1、RabbitMQ交换器类型:
(1)fanout :消息放到与交换机绑定的队列中。
(3)topic:消息发送到bindingKey和routingKey模糊匹配的队列中,*代表一个单词,#匹配0或多个单词。
(4)headers:消息根据消息内容的headers属性匹配,性能较差不实用。
2、RabbitMQ 怎么实现延迟消息队列?
延迟队列的实现有两种方式:
通过消息过期后进入死信交换器,再由交换器转发到延迟消费队列,实现延迟功能;
使用 RabbitMQ-delayed-message-exchange 插件实现延迟功能。
3 消息重复
一般消息中间件的消息传输保障分为三个层级:
(1)At most once:最多一次,消息可能会丢失,但绝不会重复传输。
(2)At least once: 最少一次,消息绝不会丢失,但可能会重复传输。
(3)Exactly once:恰好一次,每条消息肯定会被传输一次且仅传输一次。
RabbitMQ支持其中的最多一次和最少一次。
造成消息重复的根本原因是:网络不可达。只要通过网络交换数据,就无法避免这个问题。所以解决这个问题的办法就是绕过这个问题。那么问题就变成了:如果消费端收到两条一样的消息,应该怎样处理?
消费端处理消息的业务逻辑保持幂等性。也可以依赖数据库,保证每条消息都有唯一编号且保证消息处理成功与去重表的日志同时出现。
第 1 条很好理解,只要保持幂等性,不管来多少条重复消息,最后处理的结果都一样。第 2 条原理就是利用一张日志表来记录已经处理成功的消息的 ID,如果新到的消息 ID 已经在日志表中,那么就不再处理这条消息。
第 1 条解决方案,很明显应该在消费端实现,不属于消息系统要实现的功能。 第 2 条可以消息系统实现,也可以业务端实现。正常情况下出现重复消息的概率其实很小,如果由消息系统来实现的话,肯定会对消息系统的吞吐量和高可用有影响,所以最好还是由业务端自己处理消息重复的问题,这也是 RabbitMQ 不解决消息重复的问题的原因。
如果上面两种情况还不行,上大招。准备一个第三方介质,来做消费记录。以redis为例,给消息分配一个全局id,只要消费过该消息,将<id,message>以K-V形式写入redis。那消费者开始消费前,先去redis中查询有没消费记录即可。
RabbitMQ 不保证消息不重复,如果你的业务需要保证严格的不重复消息,需要你自己在业务端去重。
4 RabbitMQ如何防止消息丢失、可靠送达
(1)Exchange持久化/Queue持久化/Message持久化发送
(2)消息确认机制
发送方确认:如果消息没有到exchange,则confirm回调,ack=false,如果消息到达exchange,则confirm回调,ack=true
exchange到queue成功,则不回调return,exchange到queue失败,则回调return(需设置mandatory=true,否则不回回调,消息就丢了)
另外在消息消费方进行手动确认(设置autoAck为false),分情况判断:成功则返回ack,失败可以拒绝接收,可以重新放回队列
(3)备份交换器
如果不想使用回调机制使生产者代码变得复杂,又不想消息丢失,可以使用备份交换器。可以将未被路由的消息存储在RabbitMQ中,再在需要的时候去处理这些消息。注意:消息被重新发送到备份交换器的路由键和从生产者发出的路由键是一样的。
(4)镜像队列
相当于配置了副本,如果主节点挂掉则会自动切换到从节点,可有效保证高可用性。
(5)事务机制
txSelect、txCommit、txRollback方法,解决消息发送方和RabbitMQ之间消息确认的问题,只有消息成功被RabbitMQ接收,事务才能提交成功。但是事务机制耗费性能,推荐使用发送发确认机制。
(5)消息补偿机制(用户自己实现)
在消息发送、接受时记录DB日志,定时轮训DB日志,查明哪些发送消息没有成功消费,启动重新发送消息机制。
这种方式也可以用来防止重复消费:消费者每次执行查询前,首先在DB上查询任务的执行状态,若处于「取消/失败/成功」则表示已经由其它消费者消费过,那么直接返回ACK状态码给MQ,将消息从MQ中移除;
5、消费端要点
(1)channel.basicQos方法设置信道上的消费者所能保持的最大未确认消息的数量。只适用于推模式。
(2)RabbitMQ不能保证消息的顺序性,要保证消息的顺序性,需要业务方使用RabbitMQ之后做进一步的处理,比如在消息体内添加全局有序标识(类似SequenceID)来实现。
6、使用rabbitmq的场景
1.服务间异步通信
5 RPC调用:通过回调队列实现RPC调用
转载地址:http://qibii.baihongyu.com/