前言
关于消息队列,笔者依稀记得多年前刚毕业实习的时候,由于业务上的需要,有过一段时间的研究,那时候研究的目的是要引入一个更好的消息队列中间件来解决公司门店数据与总部机房数据通讯的问题,只可惜那时候笔者经验尚浅,并没有对消息队列有更深入的理解。
不过出于开发的需要,最近又开始消息队列的学习,并将学习笔记整理成这篇文章,以备查验。
什么是队列
队列(Queue
)是一种常见的数据结构,其最大的特性就是先进先出(Firist In First Out
),作为最基础的数据结构,队列应用很广泛,比如我们熟知的Redis
基础数据类型List
,其底层数据结构就是队列。
什么是消息队列
消息队列(Messaeg Queue
)是一种使用队列(Queue)作为底层存储数据结构,可用于解决不同进程与应用之间通讯的分布式消息容器,也称为消息中间件。
目前使用得比较多的消息队列有ActiveMQ
,RabbitMQ
,Kafka
,RocketMQ
等。
什么是RabbitMQ
RabbitMQ
是用Erlang
语言开发的一个实现了AMQP协议
的消息队列服务器,相比其他同类型的消息队列,最大的特点在保证可观的单机吞吐量的同时,延时方面非常出色。
RabbitMQ
支持多种客户端,比如:Python
、Ruby
、.NET
、Java
、JMS
、C
、PHP
、ActionScript
、XMPP
、STOMP
等。
AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。
消息队列的应用场景
消息队列使用广泛,其应用场景有很多,下面我们列举比较常见的五个场景。
消息通讯
消息队列最主要功能收发消息,其内部有高效的通讯机制,因此非常适合用于消息通讯。
我们可以基于消息队列开发点对点聊天系统
也可以开发广播系统,用于将消息广播给大量接收者。
异步处理
一般我们写的程序都是顺序执行(同步执行),比如一个用户注册函数,其执行顺序如下:
-
1.写入用户注册数据。 -
2.发送注册邮件。 -
3.发送注册成功的短信通知。 -
4.更新统计数据。
按照上面的执行顺序,要全部执行完毕,才能返回成功,但其实在第1步执行成功后,其他的步骤完全可以异步执行,我们可以将后面的逻辑发给消息队列,再由其他程序异步执行,如下所示:
使用消息队列进行异步处理,可以更快地返回结果,加快服务器的响应速度,提升了服务器的性能。
服务解耦
在我们的系统中,应用与应用之间的通讯是很常见的,一般我们应用之间直接调用,比如说应用A调用应用B的接口,这时候应用之间的关系是强耦合的。
如果应用B处于不可用的状态,那么应用A也会受影响。
在应用A与应用B之间引入消息队列进行服务解耦,如果应用B挂掉,也不会影响应用A的使用。
流量削峰
对于高并发的系统来说,在访问高峰时,突发的流量就像洪水般向应用系统涌过来,尤其是一些高并发写操作,随时会导致数据库服务器瘫痪,无法继续提供服务。
而引入消息队列则可以减少突发流量对应用系统的冲击。消息队列就像“水库”一样,拦蓄上游的洪水,削减进入下游河道的洪峰流量,从而达到减免洪水灾害的目的。
这方面最常见的例子就是秒杀系统,一般秒杀活动瞬间流量很高,如果流量全部涌向秒杀系统,会压垮秒杀系统,通过引入消息队列,可以有效缓冲突发流量,达到“削峰填谷”的作用。
RabbitMQ安装与启动
RabbitMQ
支持Linux
、Windows
,Unix
、MacOS
等多种操作系统,我们可以根据自己的操作系统来安装对应的版本,下面我们只讲解如何在Cnetos7
上安装,和使用Docker
进行安装。
更多安装详细信息,可查看官网
在Cnetos7上的安装
下面演示
Erlang
和RabbitMQ
的安装,我们使用rpm
的一键安装包,这种方式比较方便,比较适合初学者。
基础依赖安装
如果你的操作系统是Linux的最小安装包,那么应该有很多基础的依赖包没有安装,在安装RabbitMQ之前,需要安装好这些基础依赖包,可以运行如下命令:
$ sudo yum install openssql openssl-devel make gcc gcc-c++ kernel-devel
安装Socat
RabbitMQ
依赖于Socat
,因此在安装RabbitMQ
前要安装Socat
,如下:
$ sudo yum install -y socat
安装Erlang
因为RabbitMQ
是用Erlang
语言开发,所以在安装RabbitMQ
前,要先安装Erlang
运行环境,我们使用Erlang
语言的rpm
安装包。
# 下载
$ wget https://github.com/rabbitmq/erlang-rpm/releases/download/v22.3/erlang-22.3-1.el7.x86_64.rpm
# 安装
$ rpm -ivh erlang-22.3-1.el7.x86_64.rpm
安装RabbitMQ
上面所说的依赖安装完成后,最后我们可以运行下面的命令安装RabbitMQ:
# 下载
$ wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.8.3/rabbitmq-server-3.8.3-1.el7.noarch.rpm
# 安装
$ rpm -ivh rabbitmq-server-3.8.3-1.el7.noarch.rpm
启动与关闭
安装完成之后,可以使用rabbitmq-server
命令启动服务器,如下:
# 直接启动
$ sudo rabbitmq-server
# -detached为可选参数,表示后台开启
$ sudo rabbitmq-server -detached
启动成功,输出如下:
如果要关闭,则可以使用下面的命令:
#关闭RabbitMQ服务:
$ sudo rabbitmqctl stop
插件管理
上面我们使用rabbitmq-server
启动服务器,也可以使用rabbitmqctl
命令管理服务器,包括创建交换机、队列、用户管理等操作,除了命令管理工具,RabbitMQ还提供了Web管理工具,而Web管理工具作为RabbitMQ的插件,如果要开启,可以使用下面的命令 :
rabbitmq-plugins是RabbitMQ管理插件的命令。
$ sudo rabbitmq-plugins enable rabbitmq_management
启动插件后,我们再启动服务器,最后一行显示运行了3个插件,如下:
重新启动服务器后,可以打开浏览器访问RabbitMQ的Web管理界面
Web管理程序的端口号是15672,在浏览器中输入http://localhost:15672,即可以访问。
Docker上的安装
上面演示的是直接在操作系统上安装RabbitMQ
的过程,如果你本地有安装Docker
运行环境,那么可以下载RabbitMQ
的Docker
镜像进行安装,这种方式很方便,也不需要自己安装RabbitMQ
依赖。
可以Docker Hub上查询我们需要的RabbitMQ镜像包,如下:
我们选择以tag
带management后缀的镜像, 这表示该版本带有Web管理界面。
# 拉取镜像包
docker pull rabbitmq:3.8.3-management
# 启动镜像
docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 -v `pwd`/data:/var/lib/rabbitmq --hostname myRabbit -e RABBITMQ_DEFAULT_VHOST=my_vhost -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin rabbitmq3.8.3-management
核心概念
RabbitMQ
有属于自己的一套核心概念,对这些概念的理解很重要,只有理解了这些核心概念,才有可能建立对RabbitMQ
的全面理解。
Broker
Broker
概念比较简单,我们可以把Broker
理解为一个RabitMQ Server
。
Producer与Consumer
生产者与消费者相对于RabbitMQ
服务器来说,都是RabbitMQ
服务器的客户端。
-
生产者(Producer):连到 RabbitMQ
服务器,将消息发送到RabbitMQ
服务器的队列,是消息的发送方。 -
消费者(Consumer):连接到 RabbitMQ
则是为了消费队列中的消息,是消息的接收方。
生产者与消费者一般由我们的应用程序充当。
Connection
Connection
是RabbitMQ
内部对象之一,用于管理每个到RabbitMQ
的TCP
网络连接。
Channel
Channel
是我们与RabbitMQ
打交道的最重要的一个接口,我们大部分的业务操作是在Channel
这个接口中完成的,包括定义Queue
、定义Exchange
、绑定Queue
与Exchange
、发布消息等
Exchnage
消息交换机,作用是接收来自生产者的消息,并根据路由键转发消息到所绑定的队列。
生产者发送上的消息,就是先通过Exchnage
按照绑定(binding
)规则转发到队列的。
交换机类型(Exchange Type
)有四种:fanout
、direct
、topic
,headers
,其中headers
并不常用。
-
fanou
t:这种类型不处理路由键(RoutingKey
),很像子网广播,每台子网内的主机都获得了一份复制的消息,发布/订阅模式就是指使用fanout
交换机类型,fanout
类型交换机转发消息是最快的。 -
direct
:模式处理路由键,需要路由键完全匹配的队列才能收到消息,路由模式使用的是direct
类型的交换机。 -
topic
:将路由键和某模式进行匹配。主题模式使用的是topic
类型的交换机。
路由模式,发布订阅模式,主题模式,这些工作模式我们下面会讲。
Queue
Queue
,即队列,RabbitMQ
内部用于存储消息的对象,是真正用存储消息的结构,在生产端,生产者的消息最终发送到指定队列,而消费者也是通过订阅某个队列,达到获取消息的目的。
Binding
Binding
是一种操作,其作用是建立消息从Exchange
转发到Queue
的规则,在进行Exchange
与Queue
的绑定时,需要指定一个BindingKey
,Binding操作一般用于RabbitMQ
的路由工作模式和主题工作模式。
BindingKey
的概念,我们下面在讲RabbitMQ
的工作模式会详细讲解。
Virtual Host
Virutal host
也叫虚拟主机,一个VirtualHost
下面有一组不同Exchnage
与Queue
,不同的Virtual host
的Exchnage
与Queue
之间互相不影响。
应用隔离与权限划分,Virtual host
是RabbitMQ中最小颗粒的权限单位划分。
如果要类比的话,我们可以把Virtual host
比作MySQL
中的数据库,通常我们在使用MySQL
时,会为不同的项目指定不同的数据库,同样的,在使用RabbitMQ
时,我们可以为不同的应用程序指定不同的Virtual host
。
上面我们一一列举了
RabbitMQ
的核心概念,通过下面的示意图,我们可以更清晰地了解它们之间的关系。
工作模式
RabbitMQ
一共有六种工作模式,分别为简单模式、工作队列模式、发布/订阅模式、路由模式、主题模式和RPC
模式,RPC
模式并不常用,因此我们下面只讲前面五种工作模式。
简单(simple)模式
simple
模式,是RabbitMQ
几种模式中最简单的一种模式,其结构如下图所示:
从上面的示意图,我们可以看出simple
模式有以下几个特征:
-
只有一个生产者、一个消费者和一个队列。 -
生产者和消费者在发送和接收消息时,只需要指定队列名,而不需要指定发送到哪个 Exchange
,RabbitMQ
服务器会自动使用Virtual host
的默认的Exchange
,默认Exchange
的type
为direct
。
工作(work)模式
在simple
模式下只有一个生产者和消费者,当生产者生产消息的速度大于消费者的消费速度时,我们可以添加一个或多个消费者来加快消费速度,这种在simple
模式下增加消费者的模式,称为work
模式,如下图所示:
work
模式有以下两个特征:
-
可以有多个消费者,但一条消息只能被一个消费者获取。 -
发送到队列中的消息,由服务器平均分配给不同消费者进行消费。
发布/订阅(pub/sub)模式
work
模式可以将消息转到多个消费者,但每条消息只能由一个消费者获取,如果我们想一条消息可以同时给多个消费者消费呢?
这时候就需要发布/订阅模式,其示意图如下所示:
从上面的示意图我们可以看出来,在发布/订阅模式下,需要指定发送到哪个Exchange
中,上面图中的X表示Exchange
。
-
发布/订阅模式中, Echange
的type
为fanout
。 -
生产者发送消息时,不需要指定具体的队列名, Exchange
会将收到的消息转发到所绑定的队列。 -
消息被 Exchange
转到多个队列,一条消息可以被多个消费者获取。
路由(routing)模式
前面几种模式,消息的目标队列无法由生产者指定,而在路由模式下,消息的目标队列,可以由生产者指定,其示意图如下所示:
从上面示意图,我们可以看出路由模式有以下特征:
-
路由模式下 Exchange
的type为direct
。 -
消息的目标队列可以由生产者按照 routingKey
规则指定。 -
消费者通过 BindingKey
绑定自己所关心的队列。 -
一条消息队可以被多个消息者获取。 -
只有 RoutingKey
与BidingKey
相匹配的队列才会收到消息。
RoutingKey
用于生产者指定Exchange
最终将消息路由到哪个队列,BindingKey
用于消费者绑定到某个队列。
主题(topic)模式
主题模式是在路由模式的基础上,将路由键和某模式进行匹配。其中#
表示匹配多个词,*
表示匹配一个词,消费者可以通过某种模式的BindKey来达到订阅某个主题消息的目的,如示意图如下所示:
-
主题模式Exchange的type取值为topic。 -
一条消息可以被多个消费者获取。
几种常见消息队列的对比
除了RabbitMQ
之外,还有其他比较常见的消息队列中间件,如Kafka
,RocketMQ
,ActiveMQ
等,下面的表格中列举了这几种消息队列的差异:
消息队列 | RabbitMQ | ActiveMQ | RocketMQ | Kafka |
---|---|---|---|---|
所属公司/社区 | Mozilla Public License | Apache | Ali | Apache |
成熟度 | 成熟 | 成熟 | 比较成熟 | 成熟 |
授权方式 | 开源 | 开源 | 开源 | 开源 |
开发语言 | Erlang | Java | Java | Scala & Java |
客户端支持语言 | 官方支持Erlang,java,Ruby等,社区产出多种语言API,几乎支持所有常用语言 | JAVA,C++,pyhton,php,perl,net等 | java,c++ | 官方支持java,开源社区有多种语言版本,如PHP,python,go,c/c++,ruby,node.js等语言 |
协议支持 | 多协议支持AMQP,XMPP,SMTP,STOMP | OpenWire,STOMP,REST,XMPP/AMOP | 自定义的一套 | 自定义协议 |
消息批量操作 | 不支持 | 支持 | 支持 | 支持 |
消息推拉模式 | 多协议,pull/push均有支持 | 多协议pull/push均有支持 | 多协议,pull/push均有支持 | pull |
HA | master/slave模式 | 基于zookeeper+LevelDB的master-slave | 支持多master模式,多master多slave模式,异步复制模式 | 支持replica机制,leader宕掉后,备份自动顶替,并重新选择leader |
数据可靠性 | 可以保证数据不丢,有slave备份 | master/slave | 支持异步实时刷盘,同步刷盘,同步复制,民步复制 | 数据可靠,并且有replica机制,有容错容灾能力 |
单机吞吐量 | 其次(万级) | 最差(万级) | 最高(十万级) | 次之(十万级) |
消息延迟 | 微秒级 | 比Kafka快 | 毫秒级 | |
持久化能力 | 内存、文件、支持数据堆积,但数据堆积反过来影响生产速率 | 内存、文件、数据库 碰盘文件 | 磁盘文件 | 磁盘文件,只要磁盘容量够,可以做到无限消息堆积 |
是否有序 | 若想有序,只能使用一个client | 可以支持有序 | 有序 | 多client保证有序 |
事务 | 支持 | 支持 | 支持 | 不支持 |
集群 | 支持 | 支持 | 支持 | 支持 |
负载均衡 | 支持 | 支持 | 支持 | 支持 |
管理界面 | 较好 | 一般 | 命令行界面 | 官方只提供了命令行版 |
部署方式 | 独立 | 独立 | 独立 | 独立 |
小结
本文讲解了队列与RabbitMQ
的概念、如何安装RabbitMQ
、RabbitMQ
的核心概念以及几种工作模式,由于涉及到RabbitMQ
的大部分知识点,因此鉴于笔者水平有限,文章中讲解不对或不足的地方,欢迎指出,不胜感激!
原文始发于微信公众号(程序员读书):入门RabbitMQ消息队列,看这篇文章就够了
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/39108.html