RabbitMQ 基础概念的理解
预计阅读时间:12分钟
本文文字虽多,字字浓缩,静下心来,学习需要沉淀。
目录直通车
一、程序中为什么要用MQTT?
本文大部分偏向于程序设计部分的内容。
基础与原理是非常重要的。在学习 RabbitMQ 之前,先了解一下 MQTT协议。其实你也发现了都是为了解决什么问题才出现一项新技术的。
那么在程序中应用MQTT是为了解决什么问题?简单来说就是“削峰填谷”。举个栗子吧~
在以前,比如说我们秒杀抢购商品的时候,用户量在某个时间段暴增,达到峰值之后,服务器宕机,页面直接卡死报个错给用户,这样的用户体验是极差的,比如说某些学校的选课系统。为什么会发生这样的情况?页面的数据来源于数据库,当用户量在某个时间暴增的时候,此时程序不断的查询、新增,一般的数据库是承受不了这样么大的“压力”的,就会把数据库服务器直接搞宕机了。使用了消息队列机制之后,在用户秒杀抢购商品的时候,系统会提醒我们稍等排队中,而不是以前那样页面卡死或报错给用户,程序就将队列一个一个处理,就不会出现卡死的情况了。
二、MQTT是什么?
现在网上回答这个问题的文章很多,我就简单的总结后浓缩成了一句话:MQTT(Message Queuing Telemetry Transport Protocol)是基于TCP/IP 栈构建的轻量级、灵活消息队列遥测传输协议。
看完之后其实发现啥用都没有,也理解不了。管它那么多,就记住这是基于 TCP/IP 协议的创建的协议。
MQTT有两个非常重要的概念,一个是Qos(确保消息送达),另一个LWT(临终遗嘱),请看下面表格:
1、Qos(确保消息送达)
Qos |
状态描述 |
0 |
协议对此等级应用信息不要求回应确认,也没有重发机制,这类信息可能会发生消息丢失或重复,取决于TCP/IP提供的尽最大努力交互的数据包服务。 |
1(最少发送一次) |
确保信息到达,但消息重复可能发生,发送者如果在指定时间内没有收到发布确认(PUBACK)控制报文,应用信息会被重新发送。 |
2(只发送一次) |
最高级别的服务质量,消息丢失和重复都是不可接受的。 |
2、LWT(临终遗嘱)
说白了就是死前做的一件事。比如说,当客户机断开时,代理服务器就会采取相应的措施,客户端设置完成LWT之后,当代理服务器检测到客户端离线后,就会发送保存在特定主题上的 LWT 信息,让其它订阅该主题的客户端知道该节点已经意外离线。这个是MQTT利用了KeepAlive机制。
三、关于RabbitMQ
到此大家定有所疑惑,如我刚学时亦是如此。为什么要用这个玩意儿,基于MQTT开发的MQTT服务器只有只一个吗?它的运作模式是怎样的?先提三个问题在这里。
1、拍RabbitMQ的“马屁”
(1)自带“光环”
Rabbit MQ 是 Erlang语言开发的。Erlang是一种面向并发运行环境的通用编程语言(意思就是说天生自带高并发和高可用光环)。
(2)是实现了AMQP标准的消息服务器
现在市面上有如ActiveMQ、ZeroMQ、Appche Qpid等MQTT服务器,Qpid也挺不错的同样开源,为何指名点姓要RabbitMQ。
上面讲到实现了AMQP协议的MQTT服务器只有Qpid和RabbitMQ。我简单说一个理由,Qpid的社区不够活跃,不服请看下图:
(3)RabbitMQ支持持久化
保证了消息的稳定性。注意:持久化也是有缺点的,写入硬盘比写入内存性能低很多,从而降低了服务器的吞吐量,尽管使用SSD硬盘可以使事情得到缓解,但他仍然吸干了Rabbit的性能,当消息成千上万条要写入磁盘的时候,性能是很低的。所以使用者要根据自己的情况来选择。
(4)集群部署简单
不仅因为Erlang,还支持Docker。
(5)社区活跃度高
2、什么是AMQP?
这里不做重点,浓缩了以下内容:
Advanced Message Queuing Protocol,高级消息队列协议。说白了就是一个进程间传递异步消息(异步就是将消息发送给接收方时,接收方不用等待接收完成)的网络协议。
既然说到这里了,在说下同步传输,数据没有被对方确认收到则调用传输的函数就不返回,举个例子吧:你现在传输,我要亲眼看你传输完成,才去做别的事。
先来看下下面这张AMQP的模型图,在看工作过程。
发布者(Publisher)发布消息(Message),经由交换机(Exchange),交换机根据路由规则(由交换机类型和绑定(Bindings)规则)将收到的消息分发给与该交换机绑定的队列(Queue),最后 AMQP 代理(Broker)会将消息投递给订阅了此队列的消费者,或者消费者按照需求自行获取。
交换机可以有两个状态:持久化(durable)、暂存(transient)。交换机是有多种的。
持久化的交换机会在消息代理(broker)重启后依旧存在,而暂存的交换机则不会(它们需要在代理再次上线后重新被声明)。
注意:并不是所有的应用场景都需要持久化的交换机。
3、RabbitMQ的工作流程
零基础的朋友先看基本概念!
(1)基本概念
生产者(Producer):消息的创建者,负责创建和推送数据到消息服务器;
消费者(Consumer):消息的接收方,用于处理数据和确认消息;
代理(Broker):即RabbitMQ,人送外号“快递员”。
(2)工作流程分析
“粗”理解
这个图其实自己细看还是能看懂的,只是对英文有种恐惧感吧~
这里有个Create PDF的请求发送给生产者,生产者响应请求之后把消息传递到 RabbitMQ(代理机) 里面去,这里的CloudAMQP 是官方为了突出支持AMQP 标准,可以异步响应消息,不用太在意。消息首先是传递到RabbitMQ内部的交换器,然后交换器根据约定好的路由规则或算法分到队列里面去,从RabbitMQ出来之后,消息才传递给订阅了该主题的用户。
“细”理解
生产者将消息发送给代理机的细节:
下图有三类交换机:
1、Diredct,通过key绑定,只有key相同的队列才会收到消息。
2、Topic,类似正则,按照不同的模式匹配"#" 表示一个或多个单词,"*" 仅匹配一个。
3、Fanout,即广播方式,exchange把接收到的消息发给所有绑定的队列。
交换器绑定多个队列的细节:
(3)消息发送原理:
有一个误区:可能会想到我之前强调过MQTT是基于TCP/IP构建的,这里应该是通过TCP来传递消息。
实际上是通过信道(Channel)来传递消息(Message)的。对于操作系统来说,创建和销毁TCP会话是很贵的!比如说,我在文头举的例子,倘若高峰期有一千万的用户量,创建一千个TCP会话,这些会话对于系统来说,销不销毁都很贵,而且TCP会话是有限的。
所以在创建的一条TCP里使用信道来传输消息是十分可取的,如下图所示:
通过TCP连接RabbitMQ Server,Server端会给连接并认证成功的Client创建一条AMQP信道。
信道是创建在“真实”TCP上的虚拟连接,AMQP命令都是通过信道发送出去的,每个信道都会有一个唯一的ID,不论是发布消息,订阅队列或者介绍消息都是通过信道完成的。