接下来我们来整理学习下RabbitMQ的相关技能点,工欲善其事必先利其器,我们首先来理解RabbitMQ的一些特性,我们为什么选择RabbitMQ来作为我们的消息中间件。
带着问题去学习
OK,还是延续我们之前的学习特定,带着问题去学习,我们先了解下:
- 什么是rabbitMQ?
- rabbitMQ的一些主要的特性和优缺点
- rabbitMQ能为我们解决什么样的问题,主要的运用场景有哪些
- rabbitMQ的环境的搭建
RabbitMQ的简介
消息中间件
说到RabbitMQ,我们一般将其理解为消息中间件(消息队列中间件),那什么是消息中间件呢?
- 指利用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成
- 一般有两种模式:点对点(P2P,Point-to-Point)模式和发布/订阅(Pub/Sub)模式
点对点模式是基于消息队列的,消息消费者从队列中接收消息,队列的存在使得消息的异步传输存在可能
发布订阅模式定义了如何向内容节点发布和订阅消息,这个内容节点称之为主题(topic),主题可以认为是消息传递的中介。消息发布者将这个消息发布到某个主题,而消息订阅者从这个主题订阅消息,主题使得消息的订阅者和消息的发布者可以独立存在。
消息中间件的优点
消息中间件具有如下的优点:
- 解耦
- 冗余(存储)
- 扩展性
- 削峰
- 可恢复性
- 顺序保证性
- 缓冲
- 异步通讯
RabbitMQ
rabbitMQ是基于JMS的一种消息中间件的实现,他除了具有消息中间件的所有的特点,还具有如下的特点:
- 相对于Kafka,rabbitMQ虽然在效率上有所不如,但是在数据安全上更胜一筹
- rabbitMQ提供理货的路由来处理消息订阅
- rabbitMQ可以构成集群,扩展性很好
- rabbitMQ的集群可以设置虚拟节点来达到高可用
- rabbitMQ支持多种协议:AMQP、STOMP、MQTT等多种协议
- rabbitMQ含有web界面,可以监控和管理消息、集群中的节点等
- rabbitMQ提供多种插件来进行多方面的扩展
rabbitMQ的数据安全和高可用以及集群方便了我们再生产中处理一些对数据完整和安全性要求较高的功能。比如说企业与企业之间的数据通讯等
RabbitMQ的安装
我们在Centos7上安装RabbitMQ环境
当前使用的版本 erlang: otp_src_22.0.tar.gz rabbitMQ: rabbitmq-server-generic-unix-3.7.15.tar.xz
Erlang环境的搭建
RabbitMQ是基于Erlang语言开发的,所以先要安装Erlang的环境
Erlang的下载地址如下:
cd /usr/local
## 安装erlang编译需要的环境
yum install gcc glibc-devel make ncurses-devel openssl-devel xmlto
## 下载Erlang
wget http://erlang.org/download/otp_src_22.0.tar.gz
## 解压
tar -zxvf otp_src_22.0.tar.gz
## 配置
cd otp_src_22.0
./configure --prefix=/usr/local/erlang
## 编译 这里要等待n长时间
make && make install
## 修改环境变量
vi /etc/profile
## 添加
ERLANG_HOME = /usr/local/erlang
export PATH = $PATH:$ERLANG_HOME/bin
export ERLANG_HOME
## 让配置文件生效
source /etc/profile
## 查看是否安装成功
erl
RabbitMQ的环境的搭建
为了避免出现版本不兼容的问题,在搭建rabbitMQ之前,我们先来查看下erlang和rabbitMQ版本之间的关系,参考官网上:
https://www.rabbitmq.com/which-erlang.html
我们根据对照表我们下载对应的rabbitMQ的安装包
## 下载 rabbitMQ centos7版本得压缩包
https://github-production-release-asset-2e65be.s3.amazonaws.com/924551/eef64000-79e8-11e9-8998-5d172c09efb5?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20190624%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190624T090336Z&X-Amz-Expires=300&X-Amz-Signature=ef366e41fc1face2a01759cf60968f14c78ef46175fbf05999a745f7ad4d0fd2&X-Amz-SignedHeaders=host&actor_id=13399738&response-content-disposition=attachment%3B%20filename%3Drabbitmq-server-generic-unix-3.7.15.tar.xz&response-content-type=application%2Foctet-stream
官网上提供的xz的安装包,所以我们先要安装xz
## 安装xz
yum install xz
## 解压
xz -d rabbitmq-server-generic-unix-3.7.15.tar.xz
tar -xvf rabbitmq-server-generic-unix-3.7.15.tar
## 修改配置文件
vi /etc/profile
RABBITMQ_HOME=/usr/local/rabbitmq
export PATH=$PATH:$RABBITMQ_HOME/sbin
export RABBITMQ_HOME
## 配置文件生效
source /etc/profile
rabbitMQ 安装完成之后,我们需要让rabbitMQ运行起来
## 命令启动 -detached 后台启动
rabbitmq-server -detached
## 查看启动状态 有规律的一坨就是证明启动成功了
rabbitmqctl status
## 添加用户
rabbitmqctl add_user root root
## 授权
rabbitmqctl set_permissions -p / root ".*" ".*" ".*"
## 分配角色
rabbitmqctl set_user_tags root administrator
## 启用网页插件
rabbitmq-plugins enable rabbitmq_management
ok!,至此单机版的rabbitMQ环境平台就已经搭建起来了,我们可以访问: http://192.168.56.156:15672 并且输入用户名和密码:root/root
RabbitMQ的相关概念的介绍
rabbitMQ是生产者与消费者模型,相当于邮件系统,发件人相当于生产者,收件人相当云消费者,那么rabbitMQ就相当于邮局,负责接收生产者的消息,推送给消费者对应的消息
其主要的业务模型如下图:
队列
是RabbitMQ的内部对象,用于存储消息且消息只能存在队列中,这点和kafka正好相反,kafka键将数据存储在topic中。
多个消费者可以订阅同一个队列,这时队列中的消息会被平均均摊给多个消费者进行消费,而不是每个消费都接收到消息进行处理。
交换器、路由键、绑定
- Exchange
生产者将消息发送到Exchange中,然后由exchange将消息路由到一个或者多个队列中,exchange有四种类型:direct、fanout、topic、headers四种类型
- fanout
会把所有放松到该交换器的消息路由到所有与该交换器绑定的队列中
- direct
会把消息路由到BindingKey和RoutingKey相同的队列中
- topic
会把消息路由到BindingKey和RoutingKey相匹配的队列中
- headers
根据发送消息的内容中的headers属性进行匹配
- RoutingKey:
路由键,生产者将消息发送给消费者,一般会指定一个RoutingKey,用来指定这个消息的路由规则,而这个Routing Key需要和交换器类型和绑定键(Binding Key)联合才能生效
RoutingKey 决定消息的流向
- Binding
绑定:RabbitMQ通过绑定将交换器和队列关联在一起
在这里,如果利用邮局系统过来比喻的话,RoutingKey就相当于包裹上的地址,而BindingKey就相当于包裹的目的地
是的,按照上面的比喻,那么RoutingKey和BindingKey是可以是相同的,这个是正确的,这个主要是在 direct类型下,才是一样的,如果是topic类型的话,RoutingKey和BindingKey是不同的
RabbitMQ运转流程
生产者发送消息
- 生产者链接到RabbitMQ Broker,建立一个Connection,开启一个通道Channel
- 生产者声明一个交换器,并设置相关属性
- 生产者声明一个队列并且设置相关属性
- 生产者通过RoutingKey和BindingKey将交换器和队列关联在一起
- 如果找到,将消息存入到队列中
- 如果找不到,根据生产者配置的属性选择丢弃还是回退给生产者
- 关闭Channel
- 关闭Connection
消费者接受消息
- 消费者链接到RabbitMQ Broker,建立一个Connection,并开启一个通道Channel
- 消费者想RabbitMQ Broker中请求队列中消息,可能会设置相应的回调函数以及做一些准备工作
- 等待RabbitMQ Broker中回应并且投递对应队列中的消息,消费者接收消息
- 消费者确认(ack)接受到的消息
- RabbitMQ从队列中删除相应的已经被确认的消息
- 关闭Channel
- 关闭Connection
为什么使用Channel呢?
Channel是建立在Connection上的,主要是处理AMQP的指令,我们也可以是用Connection来完成Channel的工作,但是在高并发的场景下,有很多的线程需要到RabbitMQ中消费消息,如果是使用Connection来完成的话,我们需要穿件多个Connection来完成该任务,这样会造成很高的开销,很容造成系统性能瓶颈,所以我们采用NIO中的做法,选择TCP的选择复用,每个线程把持一个Channel,当每个Channel中流量不是很大时,复用单一的Connection可以有效的节省TCP的链接资源, 但是Channel中的流量很大时,再复用Connection就会产生性能瓶颈,进而使整个流量被限制,就要开辟多个Connection