什么是 RabbitMQ?
RabbitMQ是使用Erlang语言来编写的,并且是基于AMQP协议。最大的特点就是消费并不需要确保提供方存在,实现了服务之间的高度解耦。
AMQP :Advanced Message Queue,高级消息队列协议。它是应用层协议的一个开放标准,为面向消息的中间件设计,基于此协议的客户端与消息中间件可传递消息,并不受产品、开发语言等条件的限制。
好处及使用场景
好处:
1、服务间高度解耦
2、异步通信性能高
3、流量削峰
典型应用场景:
- 异步处理。把消息放入消息中间件中,等到需要的时候再去处理。
- 流量削峰。例如秒杀活动,在短时间内访问量急剧增加,使用消息队列,当消息队列满了就拒绝响应,跳转到错误页面,这样系统就不会因为超负载而崩溃。
- 应用解耦。假设某个服务A需要给许多个服务(B、C、D)发送消息,当某个服务(例如B)不需要发送消息了,服务A需要改代码再次部署;当新加入一个服务(服务E)需要服务A的消息的时候,也需要改代码重新部署;另外服务A也要考虑其他服务挂掉,没有收到消息怎么办?要不要重新发送呢?是不是很麻烦,使用MQ发布订阅模式,服务A只生产消息发送到MQ,B、C、D从MQ中读取消息,需要A的消息就订阅,不需要了就取消订阅,服务A不再操心其他的事情,使用这种方式可以降低服务或者系统之间的耦合。
- 日志处理。
mq 的缺点
1、系统可用性降低
系统引入的外部依赖越多,越容易挂掉。本来是 A 系统调用 BCD 三个系统的接口就好了, ABCD 四个系统好好的,没啥问题,加个 MQ 进来,万一MQ 挂了,导致整套系统崩溃。
2、系统复杂性提高
怎么保证消息没有重复消费?怎么处理消息丢失的情况?怎么保证消息传递的顺序性?
3、一致性问题
A 系统处理完了直接返回成功,以为你这个请求就成功了;但问题是,要是 BCD 三个系统那里,BD 两个系统写库成功了,结果 C系统写库失败了,数据就不一致了。
所以消息队列实际是一种非常复杂的架构,你引入它有很多好处,但是也得针对它带来的坏处做各种额外的技术方案和架构来规避掉。
RabbitMQ工作原理
Broker:接收和分发消息的应用,RabbitMQ Server 就是 Message Broker。
Virtual host:出于多租户和安全因素设计的,把 AMQP 的基本组件划分到一个虚拟的分组中,类似于网络中的 namespace 概念。当多个不同的用户使用同一个RabbitMQ server 提供的服务时,可以划分出多个 vhost,每个用户在自己的 vhost 创建 exchange/queue 等。
Connection:publisher/consumer 和 broker 之间的 TCP 连接。
Channel:如果每一次访问 RabbitMQ 都建立一个 Connection,在消息量大的时候建立 TCP Connection 的开销将是巨大的,效率也较低。Channel 是在 connection 内部建立的逻辑连接,如果应用程序支持多线程,通常每个 thread 创建单独的 channel 进行通讯,AMQP method 包含了 channel id 帮助客户端和 message broker 识channel,所以 channel 之间是完全隔离的。Channel 作为轻量级的Connection 极大减少了操作系统建立 TCP connection 的开销。
Exchange:message 到达 broker 的第一站,根据分发规则,匹配查询表中的 routing key,分发消息到 queue 中去。常用的类型有:direct (point-to-point), topic (publish-subscribe) and fanout (multicast)。
Queue:消息最终被送到这里等待 consumer 取走。
Binding:exchange 和 queue 之间的虚拟连接,binding 中可以包含 routing key,Binding 信息被保存到 exchange 中的查询表中,用于 message 的分发依据。
交换器(Exchange)
RabbitMQ常用的交换器类型有direct、topic、fanout、headers四种。
1、Direct Exchange
将所有发送到Direct Exchange交换器的消息转发到RoutingKey指定的队列中,也就是说路由到BindingKey和RoutingKey完全匹配的队列中。
2、Topic Exchange
将所有发送到Topic Exchange的消息转发到所有RoutingKey中指定的Topic的队列上面。Exchange将RoutingKey和某Topic进行模糊匹配,*(星号)用来表示一个单词,必须出现的;#(井号)用来表示任意数量(零个或多个)单词。例如"com.#”能匹配到“com.rabbitmq.oa”和“com.rabbitmq”;而“com.*“只能匹配到“com.rabbitmq”。
3、Fanout Exchange
该类型不处理路由键,会把所有发送到交换器的消息路由到所有绑定的队列中。优点是转发消息最快,性能最好。
4、Headers Exchange
该类型的交换器不依赖路由规则来路由消息,而是根据消息内容中的headers属性进行匹配。headers类型交换器性能差,在实际中并不常用。