- 2020年后想跳槽?MQ、ZK、Nginx、Kafk等分布式技术你都掌握了?
- 消息队列面试,你能顶得住面试官这波10大连环炮的攻势吗?
- 金三即逝,连这e V g @ 2 ; m份“Java春招手册”都没刷过,你拿什么备战银四?
前言
关于消息队列,笔者依稀记得多年前刚毕业实习的时候,由于业务上的需W U 1 P f q s要,有过一段时间的研究,那时候研究的目的是要引入一个更好T 3 Z的消息队列中间件来解决公司门店数据与总部机房数据通讯的问题,只可惜那时候笔者经验尚浅,并没有对消息队列有更深入的理解。
不过出于开发的需要,最近又开始消息队列的学习,并将学习笔记整理成` S 5 W U G & 8这篇文章,以备查验。
什么是队列
队列(Queue)是一种C 8 m j w * W ?常见h $ 1 F l l | A M的数据结构,其最大的特性就是先进先出(Firist In Fir] ( j % 0 % n (st Out),作为最基础的数据结构,队列应用很广泛,比如我们熟H 3 S l y知的Redis基础数据类型Lt j 4 ~ 6 ` 6 nist,其底层数据结构就是队列。
什么是消息队列
消息队列(Messaeg Queue)是一种使用队列(Queue)作为底层存储数据结构,可用于解决不同进程与应用之间通讯的分布式消息容器,也称为消息中z K - N ( 4间件。
目前使用得比较多的消息队列有ActiveMQ,RabbitMQ,Kafka,RocketMQ等。
什么是RabbitMQ
RabbitMQ是| 2 .用Erlang语言开发的一个实现了AMQP协议的消息队列服务器,相比其他同类型的消息队列,最大的特点在保证可观的单机吞吐量的同时,延时方面非常出色。7 d |
RabbitMQ支持多种客户端,比如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等。
AMQP,即AdvP } j v B 7 Da- 3 S S L P W Vnced Message Queuing Protocolj t y ;,高级消息队列协议,是应用层协议的一个开放标准,为面向消息K J M c Q的中间件设计。
消息队列的应用场景
消息队列使用广泛,其应用场_ W _ 6 u景有很多,下面我们列举比较常见的 5 r五个场景。
消息通讯
消息队列最主要功能收发消息,其内部有高效的通讯机制,因此非常适合用于消息通讯。
我们可以基于消息队列开发点对s u ? Q K点聊天系统
也可以开发广播系统,用于将消息广播给大量接收者。
异步处理
一般我们写的程序都是顺序执行(同步执行),比B . @ j _ g如一个用户注册函数,其执行顺序如下:
- 1.写入用户注册数据。
- 2.发送注册邮件。
- 3.发送注册成功的短信通知。
- 4.更新统计数据。
按照上面的执a G q :行顺序,要全部执行完毕,才能返回成功,但其实在第1步执行成功后,其他的步骤完全可以异步执行,我们可以将后面的逻辑发给消) V D息队列,再由其他程序异步执行,如下所示:
使用消息队列进行异步处理,可以更快地返回结果,加快服务器的响应速度,提升了服务器的性能。
服务解耦
在我们的Q g y 4 W 6 ? a系统中,应用与应用之间的通讯是很常见的,一般我们应用之间直接调用,比如说应用A调用应用B的接口,这时候应用之间的关系是强耦合的。
如果应用B处于不可用的状态,那么应用A也会受影响。
在应用A与应用B之间引入消息队列进行服务解耦,如果应用B挂掉,也不会影响8 3 ] z应用A的使用。
流量削峰
对于高并发的系统来说,V L ~ Z m在访问高峰时,突发的流量就像洪水般向应用} 3 4 | M .系统涌过来,尤其是一些高并发写操作,随时会导致数据库服务器瘫痪,无法继续提供服务。
而引入消息队列则可以减少突发流量对应用系统的冲击。消息队列就像“水库”一I d ! q Z样,拦蓄上游的洪水,削减进入下游河道的洪峰流量,从而达到减免洪水灾害的B I y ) V l .目的。
这方面最常见0 - = 2 g q $ B p的例子就是& _ O |秒杀系统,一般秒杀活动瞬间流量很高,如果流量全部涌向秒杀系统,会压垮秒杀系统,通过引入消息队列,可以有效缓冲突发流量,达到“削峰填谷”的作用。
RabbitMQ安装与启动
RabbitMQ支持Linux、Windows,Unix、MF % b )acOS等多种操作系统,我们可以根据自己的操作系统来安装对应的版本1 Y & s h T l,下面我们只讲解如何在Cnetos7上安装,和使用Docker进行安装。
更多安装详细信息,可查看官网
在Cnetos7上的安装
下面演示Erlang和RabbitMQ的安装,我们使用rpm的一键^ l k安装包,这种方式比较方便,比较适合初学者。
基础依赖安装
如果你3 H L 2 M的操作系统是Linux的最小安装包,那么应该有很w . C k ~ z多基础的依赖包没有安装,在安装RabbitMQ之前,需要安装好这些基础依赖包,可以运行 _ O如下命令:
$ sudo yum install openssql opensj } d Y n Ysl-devel make gcc gcc-c++ kernel-develT I / ! G . /
安装Socat
RabbitMQ依赖于Socat,因此在安装RabbitMQ前要安装Socat,如下:
$ sudo yum insta` 8 A A Q _ Fll -y socat
安装Erlang
因为RabbitMQ是用Erlang语言开发,所以在安装RabbitMQ前,要先安装Erlang运行环境,我们使用Erlang语言的rpm安装包。
# 下载
$ wget https://github.com/rabbu d r $itmq/erl! F . m 6 y D ; $ang-rpm/releases/download/v22.3/erlang-22.3-1.el7.x86_64.rpm
安装
安装RabbitMQ
上面所说的依赖安装完成后,最后我们可以运行下面的命令安装RabbitMQ:
# 下载
$ wget https://github.com/rabbitmq/rabbitmq-server/rel} D A T Reases/download/v3.8.3/rabbitmq-serve8 g C | ! Ur-3.8.3-1.el7.noarch.rpm
安装
$ rpt ` c { ? ( Vm -ivh rabbitmq-serverF | % e L ? b-3.8.3-1.el7.noarch.rpm
启动与关闭
安& ? J R u t `装完成之后,可以使用rabbitmq-server命令启动服务器,如下:
# 直接启动
$ sudo rabbitmq-server
-detached为可选参数,表示后台开启
$ sudo rabbitmq-server -detached
启动成t & P H m K功,输出如下q 0 C 7 G:
如果要关闭,则可以使用下面的命令:
#关闭RabbO * D = I ^ - _itMQ服务:
$ sudo rabbitmqctl stop
插件管理
上面我们使用rabbitmq-server启动服务器,也可j ^ @ q以使用rabbp G ! , nitmqctl命令管理服务器,包括创建交& R T m { S ; 0 H换机、队列、用户管理等操作,除了命令管理工具,RabbitMQ还提供了Web管理工具,而Web管理工具作为RabbitMQ的插件,如果要开启,可y j F R 2以使用下面的命令 :
rabbi/ w 8 ltmq-plugins是RabbitMQ管理插件的命令。
$ sudo rabbitmq-plui , ,gins 2 V denable rabbitmq_management
启动插件后,我们再$ = . r启动服务器,最后一行显示运行了3个插件,如下:
重` V ) 1 H a j 0新启动服务器后,可以打开浏览器访问RabbitMQ的Web管理界面
Web管理程序的端口号是156H 5 e i 1 b t = !72,在浏览器中输入http| p e ! C 2 F u://localhost:15672,即可以访问。
Docker上的安装
上| o / o a K v ~面演示的是直接在操作系统上安装RabbitMQ的过程,如果你本地有安装Docker运行环境,那么可以下载RabbitMQ的Docker镜像进行安装,这种方式很方便,也不需U ! 7 t ~ q N要自己安装RabbitMQ依赖。
可以Docker Hub上查询我们需要的RabbitMQ镜像包,如` v / Z -下:
我们选择以tag带management后缀的镜像, 这表示该版本带有W: P H x Seb管理界面。l ? T D T
# 拉取镜像4 7 = . @ ^包
docker pull rabbi: | W Otmq:3.8.3-management
启动镜像
docker run - Y [d --name rabbitmq -p 5672:5672 -p 15672:15672 -v pwd复制代码/data:/var/lib/rabbitmq --hostname myRabbit -e R0 I o h B lABBI8 ] * / W ! _TMQ_DEFAULT_VHOST=my_vhost -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin rabbitmq3.8.3-managemf , x ~ 3 .ent
核心概念
RabbitMQ有属于自己的一套M n n x核心. t ; o + B P `概念,对这些概念的理解很重要,只有理解了这些核心概念,才有可能建立对= D : YRabp 8 ! 1bitMQ的全面理解。
Broker
Broker概念比较简单,我们可以把Broker理解为一个RabitMQ Server。
Producer与Consumer
生产者与消费者$ _ @ ( 4 J 6相对于RabbitMQ服务器来说,都是RabbitMx C 1 rQ服务器的客户端。
- 生产者(Producer):连到RabbitB l DMQ服务器i 0 U x e B ) e,将消息发送到Rabbg O 6 v bitMQ服务器的队列,是消息的发送方。
- 消费者(CoG u 0 y m ;nsumer):连接到RabbitMQ则是为了消费队列中的消息,是消息的接收方。
生产者与消费者一般由我们的应用程序充当。
Connection
Connection是RabbitMQ内部对象之一,用于管理每] K ) | _个到RabbitMQ的TCP网络连接。
Channel
Channel是我们与RabbitMQ打交道的最重要的一个接口,我们大部分的业务操作是在Channel这个接口中完成的,包括定义Queue、定义Exchange、绑定Queue与Exchange、发布消息等
Exchnage
消息交换机,作用是接收来自生产者的消息,并根据路由键转( J G 8 I ^ l 7 {发消息到p . F s ^ x [ g所绑定的队列。
生产者发送上的消息,就是先通过E; Z Y 7 q z 7 Uxchnage按照绑定(binding)规则转发D f 9 : c { ?到队列的。
交换机类型(Exchanh F ;ge Type)有四种:fanout、direct、topic,headers,其中headers并不常用。
- fanout:这种类型不处理路由键(RoutingKey),很像子网广播,每台子网E q & I c 1 U b内的主机都获得了一份复制的消息,发布/订阅模式就是指使用fanout交换机类型,fanout类型交换机转发消息是最快的。
- direct:模式处理路由键,需要路由键完全匹配的队列才能收到消息,路由模式使用的是direct类型的交换机。
- topic:将路由键和某模式进行匹配。主题模式使用的是topic类型的交换机。
路由模式,发布订阅模式,主题模式,这些工作模式我们下面会讲。
Queue
Queue,即队列,RabbitMQ内部用于存D W # z h 2储消息的对象,是真正用存储消息的结构,在生产端,生产者的消息最终发送到指定队列,而消费者也是通过订阅某个队列,达到获取消息的目的。
Binding
Binding是一种操作,其作用是建立q L f t . M消息从Exchange转发L y ] i到Queue的规则,在进行ExK m { D $ Q ` uchangN K c ( J | oe与Queue的绑定时,需要指定一个BindingKey,Bindin2 Z 1 p ) +g操作一般用于RabbitMQ的路由工作模式和主题工作模式。
BindingKey的概念,我们下面在讲RabbitMQ的工作模式会详细讲解。
Virtual H) ? m t , r 7 rost
VirS : }utal host也叫虚k ~ j W R拟主机,一个VirtualHost下面有一组不同Exchnage与Queue,不同的ViV . 4 K r /rtual host的Exchn6 e uage与Queue之间互相不影响。
应用隔离与权限划分,Virtual host是RabbitMQ中最小颗粒的权限单位划分。
如果要类比的话,我们可以把VirF J ztual host比作MySQL中的数据库,通常我们在使用Myk + u L k |SQL q l 5L时,会为不同的项目指定不同的数据库,同样的,在v & G _使用RabbitMQ时,我们可以为不同的应用程序指定不同的Virtual host。
上面我们一一列举f u F c u W z l了RabbitMQ的核心概念,通过下面的示意y X ] ~图,我们可以更清晰地了解= C : t C 2 J它们之间的关系。
工作模式
RabbitMQ一共有六种工作模式,分别为简单模式、工作队列模式、发布/订阅模式、路由模式、主题模式和RPC模式,RPC模式并不常用,因此我们下面只讲前面五种工作模式。
简单(simple)模式
simple模式,是RabbitMQ几种模式中最简单的一种c 2 + & c c F _模式,其结构如下图所示:
从上面的示意图,我们可以看出simple模式有以下几b [ # T 0 a个特D q i : } 1 l r k征:
- 只有一个生产者、一个消费者和一个队列。
- 生产者和消费者在发送和接收消息时,只需要指定R F ^ 1 V T , Z c队列名,而不需要指定发送到哪个EZ } d f O 0 bxchange,RabbitMQ服务器会自[ 9 C | x M # a动使用Virtual hostk F G E k O ) o G的默认的Exchange,默认Exchan$ % !ge的type为direct。
工作(work)模式
在simple模式下只有一个生产者和消费者,当生产者生产消息的速度大于消费者的消费速度时,我们可以添加一个或多个消费者来加快消费速度,这种在simple模式下增加消费者的模式,称为work模式,如下图所示:
work模式有以下两个特征:
- 可以有多个消费者,但一条消息只能被一个消费者获取。
- 发送到队列中的消息,由服务器平均分配给不同消费者进行消费。
发布/订阅(pub/sub)模式
work模式可以E k ) } J = r 7 r将消息转到多个消费者,但每条消息只能由一个消费者获取,如果我们想一条4 z 3 { T z x消息可以同时给多个消费者消费呢?
这时候就需要发布/订阅模式,其示意图如下所示:
从上面的示意图我们可以看出来,在发布/订阅模式下,需要指定6 % C ! 8 Y v发送到哪个Exchange中,上面图中的X表示Exchange。
- 发布/订阅模式中,Echange的type为fanout。
- 生产者发送消息时,不需要指定具体的队列名,Exchange会将收到的消息转发到所绑定的队列。
- 消息被Exchange转到多个队列,一条消息可以被多个消费者获取。F h ? ! C f / [
路由(routing)模式
前面几种模式,消息的目标y r y 2 H M M队列无法由生产者指定,而在路由模式下,消息的目标队列,可以由生产者指定,其示意图如下所示:
从上面示意图,我们可以看出路由模式有以下特征:
- 路由模式下{ 1 D M D Z & UExchange的type为direct。
- 消息的目标队列可以由生产者按照routingKeyd } S I h N . E ?规则指定。
- 消费者通过B1 Z y v M ,indingKey绑定自己所关心的队列。$ $ l 5 S 3 3 `
- 一条消息队可以被多个消息者获取。
- 只有RoutingKU I 3 R M $ey与BidingKey相匹配的V _ _队列才会收到d Y , l [ 9 @ J H消息。
RoutingKey用于生产者指定Exchange最终将消息路由到p Z H = ] P h x ~哪个队列,BindingKey用于消费者绑定到某个队列。
主题(topic)模式
主题模式是在路由模式的基础上,将H m 1路由键和某模式进行匹配。其中#表示匹配多个词,*表示匹配一个词,消费者可以通过某种模8 c C L W }式的BindKey来达到订阅某个主题消息的目的,如示意图如下所示:
- 主题模式Exchange的type取值为topic。
- 一条消息可以被多个消费者: D : F ! - Q X c获取。
作者:张君鸿
原文链接:https:k H b ~ y u 0 9//juejin.im/post/5e78M [ ad7456fb9a07cd52c0525