02.什么是RabbitMQ
1.1MQ(Message Queue)消息队列
消息队列中间件,是分布式系统中的重要组件
主要解决,异步处理,应用解耦,流量削峰等问题
从而实现高性能,高可用,可伸缩和最终一致性的架构
使用较多的消息队列产品:RabbitMQ,RocketMQ,ActiveMQ,ZeroMQ,Kafka等
1.2MQ的主要作用
1.2.1异步处理
例如下单系统,整体流程只需要用户下单、支付流程就结束。 但是电商公司支付所涉及的系统很多,支付时可能涉及优惠券系统、积分系统、短信系统 。假设支付花费100ms,优惠券系统、积分系统、短信系统也消耗100ms,整个花费时间就是400ms。
流程:
你们可以看到这才加了三个,我可以斩钉截铁的告诉你真正的下单流程涉及的系统绝对在10个以上(主流电商),越大的越多。
这个链路这样下去,时间长得一批,用户发现我买个东西你特么要花几十秒,垃圾电商我不在你这里买了,不过要是都像并夕夕这么便宜,真香!
但是公司没有夕夕的那个经济实力啊,那只能优化系统了。
嗯不错,链路长了就慢了,那怎么解决?
那链路长了就慢了,但是我们发现上面的流程其实可以同时做的呀,你支付成功后,我去校验优惠券的同时我可以去增减积分啊,还可以同时发个短信啊。
那正常的流程我们是没办法实现的呀,怎么办,异步。
你对比一下是不是发现,这样子最多只用100毫秒用户知道下单成功了,至于短信你迟几秒发给他他根本不在意是吧。
三个系统只需要监听队列是否有支付的消息,如果有优惠券系统去校验优惠券的同时积分系统还可以可以去增减积分啊,短信系统可以同时发个短信。
小伙子我打断你一下,你说了异步,那我用线程,线程池去做不是一样的么?
诶呀,面试官你不要急嘛,我后面还会说到的,骚等。
1.2.2解耦:
既然面试官这么问了,我就说一下为啥我们不能用线程去做,因为用线程去做,你是不是要写代码?
你一个订单流程,你扣积分,扣优惠券,发短信,扣库存。。。等等这么多业务要调用这么多的接口,每次加一个你要调用一个接口然后还要重新发布系统!
而且真的全部都写在一起的话,不单单是耦合这一个问题,你出问题排查也麻烦,流程里面随便一个地方出问题搞不好会影响到其他的点,小伙伴说我每个流程都try catch不就行了,相信我别这么做,这样的代码就像个定时炸弹 ,你不知道什么时候爆炸,平时不炸偏偏在你做活动的时候炸,你就领个P0故障收拾书包提前回家过年吧。
Tip:P0—PN 是互联网大厂经常用来判定事故等级的机制,P0是最高等级了。
但是你用了消息队列,耦合这个问题就迎刃而解了呀。
你下单了,你就把你支付成功的消息告诉别的系统,他们收到了去处理就好了,你只用走完自己的流程,把自己的消息发出去,那后面要接入什么系统简单,直接订阅你发送的支付成功消息,你支付成功了我监听就好了。
那你的流程走完了,你不用管别人是否成功么?比如你下单了积分没加,优惠券没扣怎么办?
问题是个好问题,但是没必要考虑,业务系统本身就是自己的开发人员维护的,你积分扣失败关我下单的什么事情?你管好自己下单系统的就好了。
Tip:话是这么说,但是这其实是用了消息队列的一个缺点,涉及到分布式事务的知识点,我下面会提到。
1.2.3 流量削峰
- 抢购,秒杀等业务,针对高并发的场景
- 因为流量过大,暴增会导致应用挂掉,为解决这个问题,在前端加入消息队列
- 用户的请求,服务器接收后,首先写入消息队列,如果超过队列的长度,就抛弃,甩一个秒杀结束的页面!
- 说白了,秒杀成功的就是进入队列的用户;
2.背景知识介绍
2.1 AMQP高级消息队列协议
即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议
协议:数据在传输的过程中必须要遵守的规则
基于此协议的客户端可以与消息中间件传递消息
并不受产品、开发语言等条件的限制
2.2 JMS
- Java Message Server,Java消息服务应用程序接口, 一种规范,和JDBC担任的角色类似.
- 是一个Java平台中关于面向消息中间件的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信
2.3 二者的联系
- JMS是定义了统一接口,统一消息操作;AMQP通过协议统一数据交互格式
- JMS必须是java语言;AMQP只是协议,与语言无关
2.4 Erlang语言
Erlang(['ə:læŋ])是一种通用的面向并发的编程语言,它由瑞典电信设备制造商爱立信所辖的CS-Lab开发,目的是创造一种可以应对大规模并发活动的编程语言和运行环境
最初是由爱立信专门为通信应用设计的,比如控制交换机或者变换协议等,因此非常适合构建分布式,实时软并行计算系统
Erlang运行时环境是一个虚拟机,有点像Java的虚拟机,这样代码一经编译,同样可以随处运行.
3 为什么选择RabbitMQ
我们开篇说消息队列产品那么多,为什么偏偏选择RabbitMQ呢?
先看命名:兔子行动非常迅速而且繁殖起来也非常疯狂,所以就把Rabbit用作这个分布式软件的命名(就是这么简单)
Erlang开发,AMQP的最佳搭档,安装部署简单,上手门槛低
企业级消息队列,经过大量实践考验的高可靠,大量成功的应用案例,例如阿里、网易等一线大厂都有使用
有强大的WEB管理页面
强大的社区支持,为技术进步提供动力
支持消息持久化、支持消息确认机制、灵活的任务分发机制等,支持功能非常丰富
集群扩展很容易,并且可以通过增加节点实现成倍的性能提升
总结:如果你希望使用一个可靠性高、功能强大、易于管理的消息队列系统那么就选择
RabbitMQ,如果你想用一个性能高,但偶尔丢点数据不是很在乎可以使用kafka或者zeroMQ
kafka和zeroMQ的性能爆表,绝对可以压RabbitMQ一头!
4.RabbitMQ各组件功能
Broker:消息队列服务器实体
Virtual Host:虚拟主机
- 标识一批交换机、消息队列和相关对象,形成的整体
- 虚拟主机是共享相同的身份认证和加密环境的独立服务器域
- 每个vhost本质上就是一个mini版的RabbitMQ服务器,拥有自己的队列、交换器、绑定和权限机制
- vhost是AMQP概念的基础,RabbitMQ默认的vhost是 /,必须在链接时指定
Exchange:交换器(路由)
- 用来接收生产者发送的消息并将这些消息路由给服务器中的队列
Queue:消息队列
- 用来保存消息直到发送给消费者。
- 它是消息的容器,也是消息的终点。
- 一个消息可投入一个或多个队列。
- 消息一直在队列里面,等待消费者连接到这个队列将其取走。
Banding:绑定,用于消息队列和交换机之间的关联。
Channel:通道(信道)
- 多路复用连接中的一条独立的双向数据流通道。
- 信道是建立在真实的TCP连接内的 虚拟链接
- AMQP命令都是通过信道发出去的,不管是发布消息、订阅队列还是接收消息,都是通过信道完成的
- 因为对于操作系统来说,建立和销毁TCP连接都是非常昂贵的开销,所以引入了信道的概念,用来复用TCP连接。
Connection:网络连接,比如一个TCP连接。
Publisher:消息的生产者,也是一个向交换器发布消息的客户端应用程序。
Consumer:消息的消费者,表示一个从消息队列中取得消息的客户端应用程序。
Message:消息
- 消息是不具名的,它是由消息头和消息体组成。
- 消息体是不透明的,而消息头则是由一系列的可选属性组成,这些属性包括routing-key(路由键)、priority(优先级)、delivery- mode(消息可能需要持久性存储[消息的路由模式])等。