在上篇关于消息队列的文章中,我们对 rabbitMQ 有过初步的介绍,本篇将将带你深入剖析 rabbitMQ 内部结构和使用。
一、关于 RabbitMQ
说到 RabbitMQ,相信大家都不会陌生,微服务开发中必不可少的中间件。
在上篇关于消息队列的文章中,我们了解到 RabbitMQ 本质其实是用 Erlang 开发的 AMQP(Advanced Message Queuing Protocol )的具体实现,最初起源于金融系统,主要用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面有着不俗的表现。
2010年4月,RabbitMQ 科技公司被 VMware 旗下的 SpringSource 收购,在 2013 年 5 月被并入 Pivotal 。
其实 VMware,Pivotal 本质上是一家的。不同的是,VMware 是独立上市子公司,而 Pivotal 是整合了EMC的某些资源,现在并没有上市。其中我们现在使用的 Spring 系列框架,就是 Pivotal 公司热门的产品之一。
直到后来 Pivotal 将其开源,RabbitMQ 才逐渐走向大众!
RabbitMQ 发展到今天,已经被越来越多的人认可,尤其是互联网公司,已经有着大规模的场景应用,今天我们就一起来深入了解一下 RabbitMQ。
二、RabbitMQ 模型介绍
2.1、内部结构分析
上面我们有说到 RabbitMQ 本质是 AMQP 协议的一个开源实现,在详细介绍 RabbitMQ 之前,我们先来看一下 AMQP 的内部结构图!
基本概念如下
:
-
Publisher
:消息的生产者,也是一个向交换器发布消息的客户端应用程序
-
Exchange
:交换器,用来接收生产者发送的消息并将这些消息路由给服务器中的队列
-
Binding
:绑定,
用于将消息队列和交换器之间建立关联
。一个绑定就是基于路由键将交换器和消息队列连接起来的路由规则,所以可以将它理解成一个由绑定构成的路由表。
-
Queue
:消息队列,用来保存消息直到发送给消费者
-
Connection
:网络连接,比如一个 TCP 连接
-
Channel
:信道,多路复用连接中的一条独立的双向数据流通道
-
Consumer
:消息的消费者,表示一个从消息队列中取得消息的客户端应用程序
-
Virtual Host
:虚拟主机,表示一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务器域。每个 vhost 本质上就是一个 mini 版的 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的基础,必须在连接时指定,RabbitMQ 默认的 vhost 是
/
-
-
Message
:消息实体,它由消息头和消息体组成。消息头主要由
路由键、交换器、队列、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等属性
组成,而消息体就是指具体的业务对象
相比传统的 JMS 模型,AMQP 主要多了
Exchange
、
Binding
这个新概念。
在 AMQP 模型中,消息的生产者不是直接将消息发送到
Queue
队列,而是将消息发送到
Exchange
交换器,其中还新加了一个中间层
Binding
绑定,作用就是通过
路由键Key
将交换器和队列建立绑定关系。
就好比类似
用户表
和
角色表
,中间通过
用户角色表
来将用户和角色建立关系,从而实现关系绑定,在 RabbitMQ 中,消息生产者不直接跟队列建立关系,而是将消息发送到交换器之后,由交换器通过已经建立好的绑定关系,将消息发送到对应的队列!
RabbitMQ 最终的架构模型,核心部分就变成如下图所示:
从图中很容易看出,与 JMS 模型最明显的差别就是消息的生产者不直接将消息发送给队列,而是由
Binding
绑定
决定交换器的消息应该发送到哪个队列,进一步实现了在消息的推送方面,更加灵活!
2.2、交换器分发策略
当消息的生产者将消息发送到交换器之后,是不会存储消息的,而是通过中间层绑定关系将消息分发到不同的队列上,其中交换器的分发策略分为四种:Direct、Topic、Headers、Fanout!
-
Direct
:直连类型,即在绑定时设定一个 routing_key, 消息的 routing_key 匹配时, 才会被交换器投送到绑定的队列中去,原则是
先匹配、后投送
;
-
Topic
:按照规则转发类型,支持通配符匹配,和 Direct 功能一样,但是在匹配 routing_key的时候,更加灵活,支持通配符匹配,原则也是
先匹配、后投送
;
-
Headers
:头部信息匹配转发类型,根据消息头部中的 header attribute 参数类型,将消息转发到对应的队列,原则也是
先匹配、后投送
;
-
Fanout
:广播类型,将消息转发到所有与该交互机绑定的队列上,不关心 routing_key;
2.2.1、Direct
Direct 是 RabbitMQ 默认的交换机模式,也是最简单的模式,消息中的路由键(routing key)如果和 Binding 中的 binding key 一致, 交换器就将消息发到对应的队列中。
如果传入的 routing key 为
black
,不会转发到
black.green
。Direct 类型交换器是
完全匹配、单播的模式
。
2.2.2、Topic
Topic 类型交换器转发消息和 Direct 一样,不同的是:它支持通配符转发,相比 Direct 类型更加灵活!
两种通配符:
*
只能匹配一个单词,
#
可以匹配零个或多个。
如果传入的 routing key 为
black#
,不仅会转发到
black
,也会转发到
black.green
。
2.2.3、Headers
headers 也是根据规则匹配, 相比 direct 和 topic 固定地使用 routing_key , headers 则是通过一个自定义匹配规则的消息头部类进行匹配。
在队列与交换器绑定时,会设定一组键值对规则,消息中也包括一组键值对( headers 属性),当这些键值对有一对, 或全部匹配时,消息被投送到对应队列。
此外 headers 交换器和 direct 交换器完全一致,但性能差很多,目前几乎用不到了。
2.2.4、Fanout
Fanout 类型交换器与上面几个不同,
不管路由键或者是路由模式,会把消息发给绑定给它的全部队列
,如果配置了 routing_key 会被忽略,也被成为消息广播模式。很像子网广播,每台子网内的主机都获得了一份复制的消息
fanout 类型转发消息在四种类型中是最快的。
三、RabbitMQ 安装
RabbitMQ 基于 erlang 进行通信,相比其它的软件,安装有些麻烦,为了跟生产环境保持一直,操作系统选择
CentOS7
,不过本例采用
rpm
方式安装,任何新手都可以完成安装,过程如下!
3.1、安装前命令准备
输入如下命令,完成安装前的环境准备。
yum install lsof build-essential openssl openssl-devel unixODBC unixODBC-devel make gcc gcc-c++ kernel-devel m4 ncurses-devel tk tc xz wget vim
3.2、下载 RabbitMQ、erlang、socat 的安装包
本次下载的是
RabbitMQ-3.6.5
版本,采用
rpm
一键安装,适合新手直接上手。
先创建一个
rabbitmq
目录,本例的目录路径为
/usr/app/rabbitmq
,然后在目录下执行如下命令,下载安装包!
wget www.rabbitmq.com/releases/erlang/erlang-18.3-1.el7.centos.x86_64.rpm
wget http://repo.iotti.biz/CentOS/7/x86_64/socat-1.7.3.2-5.el7.lux.x86_64.rpm
wget www.rabbitmq.com/releases/rabbitmq-server/v3.6.5/rabbitmq-server-3.6.5-1.noarch.rpm
最终目录文件如下:
3.3、安装软件包
下载完之后,按顺序依次安装软件包,这个很重要哦~
rpm -ivh erlang-18.3-1.el7.centos.x86_64.rpm
rpm -ivh socat-1.7.3.2-5.el7.lux.x86_64.rpm
rpm -ivh rabbitmq-server-3.6.5-1.noarch.rpm
安装完成之后,修改
rabbitmq
的配置,默认配置文件在
/usr/lib/rabbitmq/lib/rabbitmq_server-3.6.5/ebin
目录下。
vim /usr/lib/rabbitmq/lib/rabbitmq_server-3.6.5/ebin/rabbit.app
修改
loopback_users
节点的值!
最后只需通过如下命令,启动服务即可!
rabbitmq-server start &
运行脚本之后,如果报错,例如下图!
解决办法如下:
vim /etc/rabbitmq/rabbitmq-env.conf
在文件里添加一行,如下配置!
NODENAME=rabbit@localhost
然后,再保存!再次以下命令启动服务!
rabbitmq-server start &
通过如下命令,查询服务是否启动成功!
lsof -i:5672
如果出现
5672
已经被监听,说明已经启动成功!
3.4、启动可视化的管控台
输入如下命令,启动控制台!
rabbitmq-plugins enable rabbitmq_management
用浏览器打开
http://ip:15672
,这里的
ip
就是 CentOS 系统的 ip,结果如下:
账号、密码,默认为
guest
,如果出现无法访问,检测防火墙是否开启,如果开启将其关闭即可!
登录之后的监控平台,界面如下:
四、web界面使用
相比其他的消息队列,rabbitMQ 其中一个很明显的好处就是有 web 操作界面,而且简单易用。
进入 web 管理界面之后,可以很清晰的看到分了 6 个菜单目录,分别是:
Overview、Connections、Channels、Exchanges、Queues、Admin
。
-
Overview:总览概述,主要介绍 rabbitmq 一些基础汇总等信息
-
Connections:连接池管理,主要介绍客户端连接等信息
-
Channels:信道管理,主要介绍信道连接等信息
点击具体某个具体的信道,可以看到对应的消费队列等信息。
-
Exchanges:交换器管理,主要介绍交换器等信息
-
Admin:系统管理,主要介绍用户、虚拟主机、权限等信息
下面,我们重点介绍一些如何通过 web 页面来操作 rabbitMQ!
4.1、交换器管理
点击进入 Exchanges 菜单,最下面有一个
Add a new exchange
标签。
点击
Add a new exchange
,会展示如下信息!
-
-
-
Durability:是否持久化,Durable:持久化,Transient:不持久化
-
Auto delete:是否自动删除,当最后一个绑定(队列或者exchange)被unbind之后,该exchange 自动被删除
-
Internal:是否是内部专用exchange,是的话,就意味着我们不能往该exchange里面发消息
-
Arguments:参数,是AMQP协议留给AMQP实现做扩展使用的
我们先新建一个名称为
hello-exchange
,类型为
direct
的交换器,结果如下。
等会用于跟队列关联!
4.2、队列管理
点击进入 Queues 菜单,最下面也有一个
Add a new queue
标签。
点击标签,即可进入添加队列操作界面!
-
-
Durability:是否持久化,Durable:持久化,Transient:不持久化
-
Auto delete:是否自动删除,是的话,当队列内容为空时,会自动删除队列
-
Arguments:参数,是AMQP协议留给AMQP实现做扩展使用的
同样的,新建一个名称为
hello-mq
的消息队列,结果如下。
队列新建好了之后,继续来建立绑定关系!