RabbitMQ简介
MQ
MQ:M essage Queue 消息队列
markdown
# 何为消息队列?
消息:字符串,数字,对象,文件...... 业务中需要用到的数据都可以称为消息
队列:先进先出的数据结构
- 常用来解耦,异步消息,流量削峰,实现高性能,高可用,可伸缩,最终一致性,常用于分布式系统中
- 常见产品,RabbitMQ,RocketMQ,ActiveMQ,ZeroMQ,Kafka
解耦
在分布式系统中,A系统直接远程调用B系统,如果B系统宕机了,那么A系统调用不了,也提供不了服务
如果A和B之间引用了消息队列C,A系统将消息发送到消息队列C中,再由B系统去消息队列中订阅,那么即使B系统宕机,我们的数据还保存在中间件C上,等B系统服务再启动的时候,再去消费信息
假设订单系统调用的不止一个库存系统,还调用了支付系统,物流系统,那么如果后期再加一个评分系统,那么就得修改订单系统的代码,不符合开闭原则,如果使用了消息队列,只要再加一个评分系统订阅消息队列即可
异步消息
假设用户注册之后,需要发送短息和发送邮件双重验证,
如果以传统串行的方式,将注册信息写入到数据库中 2 秒,先发送短信,成功之后再发送邮件,成功之后返回信息给客户端,可能加起来需要7秒
如果以并行的方式,将注册信息写入到数据库中 2 秒,发送邮件3秒,加起来可能要5秒
如果以中间件的方式,将注册信息写入到数据库中 2 秒,写入到消息队列中 1 秒,这时就可以返回信息给用户了,加起来只要 3秒,而后面的发送短信和发送邮件,由各自的系统去订阅消息队列,各自处理
流量削峰
流量削锋也是消息队列中的常用场景,一般在秒杀或团抢活动中使用广泛。
应用场景:系统其他时间A系统每秒请求量就100个,系统可以稳定运行。系统每天晚间八点有秒杀活动,每秒并发请求量增至1万条,但是系统最大的处理能力只能每秒处理1000个请求,于是系统崩溃,服务器宕机。
之前架构:大量用户(100万用户)通过浏览器在晚上八点高峰期同时参与秒杀活动。大量的请求涌入我们的系统中,高峰期达到每秒钟5000个请求,大量的请求打到MySQL上,每秒钟预计执行3000条SQL。
但是一般的MySQL每秒钟扛住2000个请求就不错了,如果达到3000个请求的话可能MySQL直接就瘫痪了,从而系统无法被使用。但是高峰期过了之后,就成了低峰期,可能也就1万用户访问系统,每秒的请求数量也就50个左右,整个系统几乎没有任何压力。
引入MQ:100万用户在高峰期的时候,每秒请求有5000个请求左右,将这5000请求写入MQ里面,系统A每秒最多只能处理2000请求,因为MySQL每秒只能处理2000个请求。
系统A从MQ中慢慢拉取请求,每秒就拉取2000个请求,不要超过自己每秒能处理的请求数量即可。MQ,每秒5000个请求进来,结果只有2000个请求出去,所以在秒杀期间(将近一小时)可能会有几十万或者几百万的请求积压在MQ中。
这个短暂的高峰期积压是没问题的,因为高峰期过了之后,每秒就只有50个请求进入MQ了,但是系统还是按照每秒2000个请求的速度在处理,所以说,只要高峰期一过,系统就会快速将积压的消息消费掉。
我们在此计算一下,每秒在MQ积压3000条消息,1分钟会积压18万,1小时积压1000万条消息,高峰期过后,1个多小时就可以将积压的1000万消息消费掉。
生产者和消费者
生产者 → 消息队列 ← 消费者
生成者生产消息,投递到消息队列中
消费者订阅消息队列,消费消息
缺点
- 引入新的框架,导致系统复杂度变高,MQ宕机怎么办
- 消息丢失,消息重复消费,消息传递
常见的消息队列
RabbitMQ
-
开源
-
基于 Erlang 语言开发
-
基于 AMQP(高级消息队列协议) 标准实现
-
支持语言众多,Python,Java,C,Ruby,.NET,PHP等
-
持久化
RocketMQ
- 阿里开源
- 纯 Java 开发
- 高吞吐,高可用,适合大规模分布式系统
- 由于是阿里内部产物,很多接口和 api 不是普遍适用
ActiveMQ
- Apache 出品
- 与 Spring 容易整合
- 支持语言众多,Python,Java,C,Ruby,.NET,PHP等
ZeroMQ
- 号称史上最快的消息队列
- 类似 Socket,普通 Socket 是端对端 1:1,而 ZeroMQ 是 N:N 的关系
- 支持语言众多,Python,Java,C,Ruby,.NET,PHP等
- 非持久化
Kafka
- 高吞吐量,每秒百万级的数据
- 支持 Hadoop 并行数据加载,常用于大数据生态中
- 持久化
对比
特性 | RabbitMQ | ActiveMQ | RocketMQ | Kafka |
---|---|---|---|---|
公司 | Rabbit | Apache | 阿里 | Apache |
开发语言 | Erlang | Java | Java | Scala&Java |
消息延迟 | 微秒 | 毫秒 | 毫秒 | 毫秒 |
单机吞吐 | 万级(3) | 万级(4) | 十万级(1) | 十万级(2) |
多语言支持 | 支持Java | 支持Java | 支持Java | 支持Java |
协议 | AMQP,SMTP,STOMP,XMPP | AMQP,STOMP,REST,XMPP,OpenWire | 自定义 | 自定义,http |
社区 | 社区活跃 | 社区活跃 | 较差 | 大数据相关 |
RabbitMQ
- 基于 Erlang 语言,Eralng 专门为高并发和分布式而设计的一种语言
RabbitMQ 基础架构
- Producer 生产者
- 投递消息的一方,将消息发布到 RabbitMQ 中
- Consumer 消费者
- 接收消息的一方,订阅队列,消费消息
- Broker 服务节点
- 可以将一个 RabbitMQ Broker 看做一台 RabbitMQ 服务器
- Connection 连接
- 生产者连接 broker,消费者连接 broker
- TCP 连接
- Channel 通道
- 每次访问 RabbitMQ 都建立一个 Connection的话,会很耗费性能,好比不停的创建线程,服务器的性能都浪费在创建,和销毁上了,所以使用线程池,维护多个线程,同理,Connection 内部也维护了多个 channel,如果需要连接,只要连接 channel 即可,减少了连接的开销
- 每个 channel 独立
- Virtual Host 虚拟机
- 不同用户使用同一个队列的话,张三建立一个名为 aaa 的交换机和消息队列,李四也建立一个名为 aaa 的交换机和消息队列???会冲突
- 多个不同用户使用头一个 RabbitMQ server 时,可以划分多个 Virtual Host,每个用户在自己的 vhost 里创建 exchange 和 queue
- Exchange 交换机
- 消息到达队列时,先到达交换机,通过交换机的路由规则分配到某一个具体队列
- direct
- topic
- fanout
- ...
- Queue 队列
- 生产者的消息会被送到这里等待
- 等待消费者取走消费
- Binding 绑定
- 交换机和队列之间的连接
- 交换机和队列按照什么路由绑定
工作模式
- 简单模式
- 工作队列 WorkQueue
- 轮询
- 公平分发
- 发布订阅 Publish/Subscribe
- fanout
- 路由模式 Routing
- direct
- 主题模式 Topics
- topic
- RPC远程调用