RabbitMQ消息队列
什么时候该使用MQ?
MQ是一个互联网架构中常见的解耦利器.
什么时候不使用MQ?
上游实时关注执行结果,通常采用RPC.
什么时候使用MQ?
(1)数据驱动的任务依赖;
(2)上游不关心多下游执行结果;
(3)异步返回执行时间长;
使用场景
1.解耦:
2.异步:
3.削峰:
RabbitMQ
erlang语言开发, 基于AMQP(Advanced Message Queue Protocol)
为什么选择RabbitMQ
为什么选择RabbitMQ 现在的市面上有很多MQ可以选择,比如ActiveMQ、ZeroMQ、Appche Qpid,那问题来了为什么要选择RabbitMQ?
- 除了Qpid,RabbitMQ是唯一一个实现了AMQP标准的消息服务器;
- 可靠性,RabbitMQ的持久化支持,保证了消息的稳定性;
- 高并发,RabbitMQ使用了Erlang开发语言,Erlang是为电话交换机开发的语言,天生自带高并发光环,和高可用特性;
- 集群部署简单,正是因为Erlang使得RabbitMQ集群部署变的超级简单;
- 社区活跃度高,根据网上资料来看,RabbitMQ也是首选;
工作原理
Producer—-connection—-Broker(Exchange、Queue)—-connection—-Consumer channel
‘exchange’—-消息转发
工作模式—-fanout发布订阅模式
工作模式—-路由工作模式 direct
工作模式—-通配符工作模式 topic
工作模式—-header-rpc工作模式
交换器分类
RabbitMQ的Exchange(交换器)分为四类:
-
direct(默认)—- direct为默认的交换器类型,也非常的简单,如果路由键匹配的话,消息就投递到相应的队列
-
fanout —- fanout交换器——发布/订阅模式
fanout有别于direct交换器,fanout是一种发布/订阅模式的交换器,当你发送一条消息的时候,交换器会把消息广播到所有附加到这个交换器的队列上.
- topic——匹配订阅模式
RabbitMQ事务和Confirm发送方消息确认
生产者消息丢失,有没有办法可以解决这个问题?
RabbitMQ有两种方式来解决这个问题:
1.通过AMQP提供的事务机制实现;
2.使用发送者确认模式实现;
事务使用
事务的实现主要是对信道(Channel)的设置,主要的方法有三个:
channel.txSelect()声明启动事务模式;
channel.txComment()提交事务;
channel.txRollback()回滚事务;
Confirm发送方确认模式
Confirm发送方确认模式使用和事务类似,也是通过设置Channel进行发送方确认的.
Confirm的三种实现方式:
方式一:channel.waitForConfirms()普通发送方确认模式;
方式二:channel.waitForConfirmsOrDie()批量确认模式;
方式三:channel.addConfirmListener()异步监听发送方确认模式;
集群
一、为什么使用集群?
内建集群作为RabbitMQ最优秀的功能之一,它的作用有两个:
允许消费者和生产者在Rabbit节点崩溃的情况下继续运行;
通过增加节点来扩展Rabbit处理更多的消息,承载更多的业务量;
二、集群的特点
RabbitMQ的集群是由多个节点组成的,但我们发现不是每个节点都有所有队列的完全拷贝.
RabbitMQ节点不完全拷贝特性
为什么默认情况下RabbitMQ不将所有队列内容和状态复制到所有节点?
有两个原因:
- 存储空间——如果每个节点都拥有所有队列的完全拷贝,这样新增节点不但没有新增存储空间,反而增加了更多的冗余数据.
- 性能——如果消息的发布需安全拷贝到每一个集群节点,那么新增节点对网络和磁盘负载都会有增加,这样违背了建立集群的初衷,新增节点并没有提升处理消息的能力,最多是保持和单节点相同的性能甚至是更糟. 所以其他非所有者节点只知道队列的元数据,和指向该队列节点的指针.
三、集群异常处理
根据节点不无安全拷贝的特性,当集群节点崩溃时,该节点队列和关联的绑定就都丢失了,附加在该队列的消费者丢失了其订阅的信息,那么怎么处理这个问题呢?
这个问题要分为两种情况:
消息已经进行了持久化,那么当节点恢复,消息也恢复了;
消息未持久化,可以使用双活冗余队列,镜像队列保证消息的可靠性;
Kafka、RocketMQ、RabbitMQ都不能保证消息不重不丢(Exactly Once)
消息可靠性的服务水平:
- At most once:至多一次,允许丢消息
- At least once:至少一次,不允许丢消息,可以重复
- Exactly once:恰好一次,不允许丢也不重复
questions
1.为什么用?
解耦:
异步:
削峰:
2.各种产品比较?
产品 | 开发语言 | 单机吞吐量 | 时效性 | 高可用 | 功能特性 |
---|---|---|---|---|---|
RabbitMQ |
erlang | 万级 | us | 高、分布式 | |
Kafka |
scala | 10万级 | ms | 非常高、分布式 | |
RocketMQ |
java | 10万级 | ms | 非常高、分布式 | |
ActiveMQ |
java | 万级 | ms | 高、主从架构 |
3.消息队列的优点和缺点?
可用性降低—-集群
系统变复杂—-
数据一致性问题—-最终一致性
4.如何保证消息队列的高可用?
rabbitMQ高可用
RocketMQ高可用—-双主双从
5.如何保证消息不丢失?
分析原因
1.生产者
2.MQ
3.消费者
解决
1.confirm
2.消息持久化
3.ack确认
6.保证消息不被重复消费?
原因
根本原因是网络不可达,不可避免
1.发送时消息重复
2.消费时消费重复
解决
保证消息消费业务的幂等
1.唯一id
2.消费者根据id查询是否消费
3.消费完毕写入redis/db
4.如果已经消费就丢弃
7.如何保证消息顺序消费?
1.是否理解消息的顺序消费
全局顺序消费、局部顺序消费
解决
一个消费者一个队列
MQ使用分段锁来保证单个Queue的有序消费
8.大量消息堆积如何处理?
原因:
1.消费者出现故障
2.消费了没有ack
解决
1.恢复消费者
2.写程序转发处理
9.消息过期?
原因
设置过期时间
过期消息可以转入死信队列
解决
1.启用专门消费者消费过期消息,记录日志
2.重新查询过期消息