RabbbitMQ的简介和安装
1-1 消息队列概述
1. 队列
队列(Queue)是一种常见的数据结构,其最大的特性就是先进先出(Firist In First Out),作为最基础的数据结构,队列应用很广泛,比如我们熟知的Redis基础数据类型List,其底层数据结构就是队列。
2. 消息队列
消息(Message)是指在应用间传送的数据。消息可以非常简单,比如只包含文本字符串,JSON,也可以很复杂,比如内嵌对象。
消息队列(Messaeg Queue
)是一种使用队列(Queue)作为底层存储数据结构,可用于解决不同进程与应用之间通讯的分布式消息容器,也称为消息中间件。
从本质上说消息队列就是一个队列结构的中间件,也就是说消息放入这个中间件之后就可以直接返回,并不需要系统立即处理,而另外会有一个程序读取这些数据,并按顺序进行逐次处理。
目前使用得比较多的消息队列有ActiveMQ
,RabbitMQ
,Kafka
,RocketMQ
等。
3. 应用场景
消息队列常用的有五个场景:
- 消息通讯
- 异步处理
- 服务解耦
- 流量削峰
A. 消息通讯
消息队列最主要功能收发消息,其内部有高效的通讯机制,因此非常适合用于消息通讯。
可以基于消息队列开发点对点聊天系统,也可以开发广播系统,用于将消息广播给大量接收者。
B. 异步处理
一般写的程序都是顺序执行(同步执行),比如一个用户注册函数,其执行顺序如下:
- 写入用户注册数据
- 发送注册邮件
- 发送注册成功的短信通知
- 更新统计数据
按照上面的执行顺序,要全部执行完毕,才能返回成功,但其实在第1步执行成功后,其他的步骤完全可以异步执行,可以将后面的逻辑发给消息队列,再由其他程序异步执行,如下所示:
使用消息队列进行异步处理,可以更快地返回结果,加快服务器的响应速度,提升了服务器的性能。
C. 服务解耦
在系统中,应用与应用之间的通讯是很常见的,一般应用之间直接调用,比如说应用A调用应用B的接口,这时候应用之间的关系是强耦合的。
如果应用B处于不可用的状态,那么应用A也会受影响。
在应用A与应用B之间引入消息队列进行服务解耦,如果应用B挂掉,也不会影响应用A的使用。
使用消息队列之后,生产者并不关心消费者是谁,消费者同样不关注发送者是谁,这就是解耦,消息队列常用来解决服务之间的调用依赖关系。
D. 流量削峰
对于高并发的系统来说,在访问高峰时,突发的流量就像洪水般向应用系统涌过来,尤其是一些高并发写操作,随时会导致数据库服务器瘫痪,无法继续提供服务。
而引入消息队列则可以减少突发流量对应用系统的冲击。消息队列就像“水库”一样,拦蓄上游的洪水,削减进入下游河道的洪峰流量,从而达到减免洪水灾害的目的。
这方面最常见的例子就是秒杀系统,一般秒杀活动瞬间流量很高,如果流量全部涌向秒杀系统,会压垮秒杀系统,通过引入消息队列,可以有效缓冲突发流量,达到“削峰填谷”的作用。
1-2. RabbitMQ概述
1. 概述
RabbitMQ
是用Erlang
语言开发的一个实现了AMQP协议
的消息队列服务器,相比其他同类型的消息队列,最大的特点在保证可观的单机吞吐量的同时,延时方面非常出色。
RabbitMQ
支持多种客户端,比如:Python
、Ruby
、.NET
、Java
、JMS
、C
、PHP
、ActionScript
、XMPP
、STOMP
等。
RabbitMQ
最初起源于进入系统,用于在分布式系统中存储转发消息。
RabbitMQ的特点:
- 可靠性:RabbitMQ提供了多种技术可以在性能和可靠性之间进行权衡。这些技术包括持久性机制、投递确认、发布者证实和高可用性机制
- 灵活的路由:消息在到达队列前是通过交换机进行路由的。RabbitMQ为典型的路由逻辑提供了多种内置交换机类型
- 集群:在相同局域网中的多个RabbitMQ服务器可以聚合在一起,作为一个独立的逻辑代理来使用
- 联合:对于服务器来说,它比集群需要更多的松散和非可靠链接。为此RabbitMQ提供了联合模型
- 高可用队列:在同一个集群里,队列可以被镜像到多个机器中,以确保当其中某些硬件出现故障后,消息仍然安全
- 多协议:支持多种消息协议的消息传递
- 广泛的客户端:支持多种客户端
- 可视化管理工具:RabbitMQ附带了一个易于使用的可视化管理工具,它可以帮助你监控消息代理的每一个环节
- 追踪:RabbitMQ提供了对异常行为的追踪的支持,能够发现问题所在
- 插件系统:RabbitMQ附带了各种各样的插件来进行扩展,甚至可以写插件来使用
2. AMQP协议
RabbitMQ是一个实现了AMQP协议的消息队列服务器,这里先来介绍以下AMQP。
AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计,它支持符合要求的客户端应用(application)和消息中间件代理(messaging middleware broker)之间进行通信。
消息代理(message brokers)从发布者(publishers)亦称生产者(producers)那儿接收消息,并根据既定的路由规则把接收到的消息发送给处理消息的消费者(consumers)。
由于AMQP是一个网络协议,所以这个过程中的发布者,消费者,消息代理 可以存在于不同的设备上。
AMQP 0-9-1的工作过程如下图:
消息(message)被发布者(publisher)发送给交换机(exchange),交换机常常被比喻成邮局或者邮箱。然后交换机将收到的消息根据路由规则分发给绑定的队列(queue)。最后AMQP代理会将消息投递给订阅了此队列的消费者,或者消费者按照需求自行获取。
发布者(publisher)发布消息时可以给消息指定各种消息属性(message meta-data)。有些属性有可能会被消息代理(brokers)使用,然而其他的属性则是完全不透明的,它们只能被接收消息的应用所使用。
从安全角度考虑,网络是不可靠的,接收消息的应用也有可能在处理消息的时候失败。
基于此原因,AMQP模块包含了一个消息确认(message acknowledgements)的概念:当一个消息从队列中投递给消费者后(consumer),消费者会通知一下消息代理(broker),这个可以是自动的也可以由处理消息的应用的开发者执行。当“消息确认”被启用的时候,消息代理不会完全将消息从队列中删除,直到它收到来自消费者的确认回执(acknowledgement)。
在某些情况下,例如当一个消息无法被成功路由时,消息或许会被返回给发布者并被丢弃。或者,如果消息代理执行了延期操作,消息会被放入一个所谓的死信队列中。此时,消息发布者可以选择某些参数来处理这些特殊情况。
队列,交换机和绑定统称为AMQP实体(AMQP entities)。
3. 相关概念
RabbitMQ
有属于自己的一套核心概念,对这些概念的理解很重要,只有理解了这些核心概念,才有可能建立对RabbitMQ
的全面理解。
A. 生产者,Producer
生产者连接到RabbitMQ服务器,然后将消息发送到RabbitMQ服务器的队列,是消息的发送方。
消息一般可以包含2个部分:
- 消息体:消息体也可以称之为payload,在实际应用中,消息体一般是一个带有业务逻辑结构的数据,比如一个 JSON 字符串
- 标签(Label)
B. 消费者,Consumer
消费者连接到RabbitMQ服务器,并订阅到队列上,是消息的接收方。
当消费者消费一条消息时,只是消费消息的消息体(payload)。
C. Broker
Broker,是消息中间件的服务节点。
对于RabbitMQ来说,一个RabbitMQ Broker可以简单地看作一个RabbitMQ服务节点,或者 RabbitMQ服务实例 。
D. Queue,队列
队列,Queue,是RabbitMQ内部用于存储消息的对象,是真正用存储消息的结构。
在生产端,生产者的消息最终发送到指定队列,而消费者也是通过订阅某个队列,达到获取消息的目的。
RabbitMQ中消息都只能存储在队列中,队列的特性是先进先出。
队列收到的消息,必须是由Exchange转发过来的。
一个队列中的消息数据可能来自于多个Exchange,一个Exchange中的消息数据也可能推送给多个队列,它们之间的关系是多对多的。
E. Exchange
Exchange,消息交换机,作用是接收来自生产者的消息,并根据路由键转发消息到所绑定的队列。
生产者发送的消息,每个消息都会带有一个路由键(RoutingKey),就是一个简单的字符串,消息先通过Exchange按照绑定(binding)规则转发到队列的。
一个队列中的消息数据可能来自于多个Exchange,一个Exchange中的消息数据也可能推送给多个队列,它们之间的关系是多对多的。
交换机拿到一个消息之后将它路由给一个或多个队列。它使用哪种路由算法是由交换机类型和被称作绑定(bindings)的规则所决定的。
交换机类型(Exchange Type)共有4种:
- fanout:扇型交换机,这种类型不处理路由键(RoutingKey),类似于广播,把所有发送到交换机上的消息都会发送给与该交换机绑定的所有队列上。该类型下发送消息是最快的。
- direct:直连交换机,模式处理路由键(RoutingKey),需要路由键完全匹配的队列才能收到交换机的消息。这种模式使用最多。
- topic:主题交换机,将路由键和某模式进行匹配。
- headers:头交换机,一般很少用。
F. Binding
Binding
是一种操作,其作用是建立消息从Exchange
转发到Queue
的规则,在进行Exchange
与Queue
的绑定时,需要指定一个BindingKey
,Binding操作一般用于RabbitMQ
的路由工作模式和主题工作模式。
G. vhosts
vhosts,虚拟主机,Virutal host
也叫虚拟主机,一个Virtual Host
下面有一组不同Exchnage
与Queue
,不同的Virtual host
的Exchnage
与Queue
之间互相不影响。
应用隔离与权限划分,Virtual host
是RabbitMQ中最小颗粒的权限单位划分。
如果要类比的话,可以把Virtual host
比作MySQL
中的数据库,通常我们在使用MySQL
时,会为不同的项目指定不同的数据库,同样的,在使用RabbitMQ
时,可以为不同的应用程序指定不同的Virtual host
。
RabbitMQ 当中,用户只能在虚拟主机的粒度进行权限控制。因此,如果需要禁止 A 组访问 B 组的交换机 / 队列 / 绑定,必须为 A 和 B 分别创建一个虚拟主机。
每一个 RabbitMQ 服务器都有一个默认的虚拟主机 “/” 。
一个RabbitMQ的Server上可以有多个vhosts,用户与权限设置就是依附于vhosts。
H. Connection
Connection
是RabbitMQ
内部对象之一,偏物理的概念,是一个物理连接,用于管理每个到RabbitMQ
的TCP
网络连接。
生产者、消费者和Broker之间就是通过Connection进行连接的。
I. Channel
Channel
,信道,是与RabbitMQ
打交道的最重要的一个接口,是偏逻辑上的概念,在一个连接(Connection)中可以创建多个Channel。
大部分与RabbitMQ的相关操作是在Channel
这个接口中完成的,包括定义Queue
、定义Exchange
、绑定Queue
与Exchange
、发布消息等。
可以参考如图:
2-1. 安装
这里只介绍Windows的安装和CentOS7下的安装,官网还提供了Ubuntu、Mac甚至docker下的安装等。
RabbitMQ服务器的代码是使用erlang语言编写的,所以是需要先安装erlang语言的。
注意:RabbitMQ的版本依赖于Erlang的版本,具体可参考:https://www.rabbitmq.com/which-erlang.html
1. Windows安装
A. 安装erlang
先通过官网下载erlang:官网下载地址
下载exe文件然后安装
安装好了之后需要设置环境变量:
我的电脑 - 右击属性 - 高级系统设置 - 环境变量 - 用户变量/系统变量新建一个变量:
变量名为:ERLANG_HOME,变量值为erlang的安装目录
还需要加入到Path中:%ERLANG_HOME%\bin
然后打开命令行,输入erl,如果显示erlang的版本信息即表示安装成功:
B. 安装RabbitMQ
通过官网下载RabbitMQ:官网下载地址
双击安装即可
C. 安装Web管理【非必须】
该步骤非必须,RabbitMQ还提供了Web管理工具,而Web管理工具作为RabbitMQ的插件,相当于是一个后台管理页面,方便在浏览器中查看
进入到sbin目录下,打开命令行输入:
./rabbitmq-plugins.bat enable rabbitmq_management
安装成功之后,浏览器输入http://localhost:15672即可访问管理页面
默认的账号和密码都是guest
注意:一般会创建个新的管理员用户,不使用默认的guest,guest用户只能在localhost下访问,如果在内网的其他机器访问的话,登录的时候会报错:
2. Centos 7安装
A. 安装erlang
关于安装erlang,RabbitMQ官网提供了4种方式安装:
我这里使用第一种方式,按照Github上的安装方式
新建一个文件:/etc/yum.repos.d/rabbitmq_erlang.repo
# vim /etc/yum.repos.d/rabbitmq_erlang.repo
[rabbitmq_erlang]
name=rabbitmq_erlang
baseurl=https://packagecloud.io/rabbitmq/erlang/el/7/$basearch
repo_gpgcheck=1
gpgcheck=1
enabled=1
# PackageCloud's repository key and RabbitMQ package signing key
gpgkey=https://packagecloud.io/rabbitmq/erlang/gpgkey
https://dl.bintray.com/rabbitmq/Keys/rabbitmq-release-signing-key.asc
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
metadata_expire=300
[rabbitmq_erlang-source]
name=rabbitmq_erlang-source
baseurl=https://packagecloud.io/rabbitmq/erlang/el/7/SRPMS
repo_gpgcheck=1
gpgcheck=0
enabled=1
# PackageCloud's repository key and RabbitMQ package signing key
gpgkey=https://packagecloud.io/rabbitmq/erlang/gpgkey
https://dl.bintray.com/rabbitmq/Keys/rabbitmq-release-signing-key.asc
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
metadata_expire=300
保存之后,进行yum安装
yum install erlang
然后打开命令行,输入erl,如果显示erlang的版本信息即表示安装成功:
注意:不能直接yum install erlang
,会导致erlang的版本很低,后面安装rabbitMQ的时候会有版本冲突的
B. 安装其他依赖
除了erlang,RabbitMQ还需要安装:socat和logrotate
yum install -y socat logrotate
C. 安装RabbitMQ
这里有两种方式进行安装:
- rpm安装
- yum安装
第一种方式:rpm安装
下载RabbitMQ,具体的rpm包链接可参考:官网下载页面
wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.8.14/rabbitmq-server-3.8.14-1.el7.noarch.rpm
然后rpm安装:
rpm -ivh rabbitmq-server-3.8.14-1.el7.noarch.rpm
第二种方式:yum安装
新建一个文件:/etc/yum.repos.d/rabbitmq_server.repo
# vim /etc/yum.repos.d/rabbitmq_server.repo
[rabbitmq_server]
name=rabbitmq_server
baseurl=https://packagecloud.io/rabbitmq/rabbitmq-server/el/7/$basearch
repo_gpgcheck=1
gpgcheck=0
enabled=1
gpgkey=https://packagecloud.io/rabbitmq/rabbitmq-server/gpgkey
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
metadata_expire=300
[rabbitmq_server-source]
name=rabbitmq_server-source
baseurl=https://packagecloud.io/rabbitmq/rabbitmq-server/el/7/SRPMS
repo_gpgcheck=1
gpgcheck=0
enabled=1
gpgkey=https://packagecloud.io/rabbitmq/rabbitmq-server/gpgkey
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
metadata_expire=300
然后yum安装:
yum install -y rabbitmq_server rabbitmq-server
通过rabbitmqctl来验证是否安装成功:
>>> rabbitmqctl version
3.8.14
D. 启动
# -detached为可选参数,表示后台开启
rabbitmq-server -detached
如果要关闭的话,可以使用:
rabbitmqctl stop
E. 安装Web管理【非必须】
rabbitmq-plugins enable rabbitmq_management
安装完成之后即可通过localhost:15672来进行访问
默认的账号和密码都是guest
注意:一般会创建个新的管理员用户,不使用默认的guest,guest用户只能在localhost下访问,如果在内网的其他机器访问的话,登录的时候会报错:
以下是添加管理员用户(这里是root):
# 添加用户
rabbitmqctl add_user root 123456
# 赋予管理员权限
rabbitmqctl set_user_tags root administrator
# 查看用户列表
rabbitmqctl list_users