一、RabbitMQ 简介
RabbitMQ 是由 LShift 提供的一个 Advanced Message Queuing Protocol (AMQP) 的开源实现,由以高性能、健壮以及可伸缩性出名的 Erlang 开发设计,因此也是继承了这些优点。
本文档旨在基于 Erlang 环境在 CentOS 7 系统上安装配置 RabbitMQ
因为 RabbitMQ 是用 Erlang 开发实现的,所以在安装 RabbitMQ 之前需要先配置完成 Erlang 的开发环境,Erlang 的具体安装配置可以参考 rabbitmq-erlang-installation。
RabbitMQ 的官方站点:https://www.rabbitmq.com
RabbitMQ 的官方下载地址:https://www.rabbitmq.com/download.html
特性 | ActiveMQ | RabbitMQ | RocketMQ | kafka |
---|---|---|---|---|
开发语言 | java | erlang | java | scala |
单机吞吐量 | 万级 | 万级 | 10万级 | 10万级 |
时效性 | ms级 | us级 | ms级 | ms级以内 |
可用性 | 高(主从架构) | 高(主从架构) | 非常高(分布式架构) | 非常高(分布式架构) |
功能特性 | 成熟的产品,在很多公司得到应用;有较多的文档;各种协议支持较好 | 基于erlang开发,所以并发能力很强,性能极其好,延时很低;管理界面较丰富 | MQ功能比较完备,扩展性佳 | 只支持主要的MQ功能,像一些消息查询,消息回溯等功能没有提供,毕竟是为大数据准备的,在大数据领域应用广。 |
二、修改主机名
RabbitMQ 是通过主机名进行访问的,必须指定能访问的主机名,搭建好后修改主机名(hosts、hostname)会导致服务内容全清空(如账号、权限信息)。
hostnamectl set-hostname rabbitmq1
hostnamectl set-hostname rabbitmq2
hostnamectl set-hostname rabbitmq3
每个节点添加hosts
192.168.50.134 rabbitmq1
192.168.50.135 rabbitmq2
192.168.50.136 rabbitmq3
三、安装rabbitmq
本次我们在 CentOS 7 上安装 RabbitMQ 服务,更为详细的或者其他系统的安装过程可以参考官方文档:https://www.rabbitmq.com/download.html
为了安装方便,本次安装方式选用 yum 的方式安装。
erlang 与 centos,rabbitmq 与 erlang,这些都是有依赖关系的,不同版本会存在不兼容性,可能导致安装完成后无法启动的情况,如果遇到此情况,可以查看官方版本兼容性文档,rabbitmq 官方给出的与 erlang/OTP 的版本兼容要求可以参考 http://www.rabbitmq.com/which-erlang.htm
1、安装依赖及rabbitmq
# yum install socat -y
# wget https://github.do/https://github.com/rabbitmq/erlang-rpm/releases/download/v23.3.4.11/erlang-23.3.4.11-1.el7.x86_64.rpm
# yum -y install erlang-23.3.4.11-1.el7.x86_64.rpm
# wget https://mirror.ghproxy.com/https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.8.27/rabbitmq-server-3.8.27-1.el7.noarch.rpm
# yum -y install rabbitmq-server-3.8.27-1.el7.noarch.rpm
2、节点修改存储位置
# mkdir -p /data/rabbitmq/{mnesia,log}
# chmod -R 777 /data/rabbitmq
# chown -R rabbitmq:rabbitmq /data/rabbitmq/mnesia
# chown -R rabbitmq:rabbitmq /data/rabbitmq/log
# vim /etc/rabbitmq/rabbitmq-env.conf
RABBITMQ_MNESIA_BASE=/data/rabbitmq/mnesia
RABBITMQ_LOG_BASE=/data/rabbitmq/log
3、所有节点启动并安装插件
systemctl enable rabbitmq-server && systemctl start rabbitmq-server
rabbitmq-plugins enable rabbitmq_prometheus # 提供对Prometheus监控系统的支持
rabbitmq-plugins enable rabbitmq_management # 提供一个基于Web的管理界面和API接口
当 RabbitMQ 服务正常启动后,我们可以查看对应的日志,日志默认在 /var/log/rabbitmq/
目录下。日志中给出了rabbitmq 启动的重要信息,如 node 名,$home 目录,cookie hash 值,日志文件,数据存储目录等,但是默认情况下没有配置文件的相关信息,我们需要手动创建配置文件
4、三台机器同步.erlang.cookie
文件
RabbitMQ 利用 erlang 的分布式特性组建集群,erlang 集群通过 magic cookie 实现,此 cookie 保存在$home/.erlang.cookie,这里即:/var/lib/rabbitmq/.erlang.cookie,需要保证集群各节点的此 cookie 一致,可以选取一个节点的 cookie,采用 scp 同步到其他节点:
# cd /var/lib/rabbitmq
# ls -al
total 8
drwxr-xr-x 3 rabbitmq rabbitmq 42 Mar 7 11:12 .
drwxr-xr-x. 28 root root 4096 Mar 7 11:01 ..
-r-------- 1 rabbitmq rabbitmq 20 Mar 7 00:00 .erlang.cookie
drwxr-x--- 2 rabbitmq rabbitmq 6 Jan 5 13:03 mnesia
# scp .erlang.cookie root@nacos02:/var/lib/rabbitmq/
# scp .erlang.cookie root@nacos03:/var/lib/rabbitmq/
5、所有节点重启服务
systemctl restart rabbitmq-server
使用以下命令查看端口开放说明正常。(其中15672和55672都是rabbitmq的管理端口,5672则是和生产者、消费者通信的端口。)
netstat -ntap | grep 5672
三、组建集群
一般情况下,如果只是为了探究 RabbitMQ 或者验证业务工程的正确性那么在本地环境或者测试环境上使用其单实例部署就可以了,但是出于 MQ 中间件本身的可靠性、并发性、吞吐量和消息堆积能力等问题的考虑,在生产环境上一般都会考虑使用 RabbitMQ 的集群方案。
1、集群模式
RabbitMQ 集群有两种模式:
- 默认模式,以两个节点 mq1 和 mq2 为例来进行说明。对于 Queue 来说,消息实体只存在于其中一个节点 mq1 或者 mq2 ,mq1 和 mq2 两个节点仅有相同的元数据,即队列的结构。当消息进入 mq1 节点的 Queue 后,consumer 从 mq2 节点消费时,RabbitMQ 会临时在 mq1 、mq2 间进行消息传输,把 A 中的消息实体取出并经过 B 发送给 consumer。所以 consumer 应尽量连接每一个节点,从中取消息。即对于同一个逻辑队列,要在多个节点建立物理 Queue。否则无论 consumer 连 mq1 或 mq2 ,出口总在 mq1,会产生瓶颈。当 mq1 节点故障后,mq2 节点无法取到 mq1 节点中还未消费的消息实体。如果做了消息持久化,那么得等 mq1 节点恢复,然后才可被消费;如果没有持久化的话,就会产生消息丢失的现象。
- 镜像模式,把需要的队列做成镜像队列,存在与多个节点属于**RabbitMQ 的 HA 方案。**该模式解决了普通模式中的问题,其实质和普通模式不同之处在于,消息实体会主动在镜像节点间同步,而不是在客户端取数据时临时拉取。该模式带来的副作用也很明显,除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通讯大大消耗掉。所以在对可靠性要求较高的场合中适用。
使用以下命令检查集群状态,目前相互独立,没有形成集群
rabbitmqctl cluster_status
2、节点rabbitmq2、rabbitmq3加入集群
rabbitmqctl stop_app
rabbitmqctl reset
# 在服务器上把该节点作为内存节点与主磁盘节点连接起来。
rabbitmqctl join_cluster --ram rabbit@rabbitmq1
rabbitmqctl start_app
RabbitMQ 节点分为内存节点和磁盘节点:
- 内存节点(RAM):内存节点将所有的队列、交换机、绑定、用户、权限和vhost的元数据定义存储在内存中
- 磁盘节点(Disk):将元数据存储在磁盘中,单节点系统只允许磁盘类型的节点,防止重启RabbitMQ的时候,丢失系统的配置信息。
如果需要切换节点类型,可以参考如下命令:
# 如果节点已是"disk"节点,可以修改为内存节点
rabbitmqctl stop_app
rabbitmqctl change_cluster_node_type ram
rabbitmqctl start_app
- RabbitMQ要求在集群中至少有一个磁盘节点,所有其他节点可以是内存节点,当节点加入或者离开集群时,必须要将该变更通知到至少一个磁盘节点。如果集群中唯一的一个磁盘节点崩溃的话,集群仍然可以保持运行,但是无法进行其他操作(增删改查),直到节点恢复, 或者可以设置两个磁盘节点,以保持有一个是可用的。
- 内存节点虽然不写入磁盘,但是它执行比磁盘节点要好。
- 如果集群中只有内存节点,那么不能停止它们,否则所有的状态,消息等都会丢失。
3、设置集群名称
rabbitmqctl -q set_cluster_name myrabbitmq
4、创建用户及其权限
# 添加账号,并设置密码
rabbitmqctl add_user admin (密码)
# 设置账号的状态
rabbitmqctl set_user_tags admin administrator
# 设置账号的权限
rabbitmqctl set_permissions -p '/' admin '.*' '.*' '.*'
# 清除用户权限
# rabbitmqctl clear_permissions -p '/' admin
# 列出账号
rabbitmqctl list_users
至此,就可以用新建的管理员账号登陆 WEB 页面了。
通过浏览器输入http://ip:15672访问RabbitMQ(默认用户名:guest 密码:guest)
5、配置镜像集群
# 对/节点配置镜像队列,使用全局复制(策略名称为 ha-all,通配符 ^ 表示匹配到的所有队列,复制到所有节点)
# rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}'
# rabbitmqctl set_policy -p /prod ha-all "^" '{"ha-mode":"all"}'
# 配置过半(N/2 + 1)复制镜像队列(复制匹配到的队列到集群中的任意两个或多个节点,而不是到所有节点)
# rabbitmqctl set_policy ha-halfmore "queueA" '{"ha-mode":"exactly", "ha-params":2}'
rabbitmqctl set_policy -p "/prod" ha-halfmore "^" '{"ha-mode":"exactly", "ha-params":2,"ha-sync-mode":"automatic"}'
# 指定优先级,数字越大,优先级越高
rabbitmqctl set_policy --priority 1 ha-all "^" '{"ha-mode":"all"}'
rabbitmqctl set_policy -p / --priority 1 ha-all "^" '{"ha-mode":"all"}'
这条命令里面 / 的意思虚拟主机vhost
每一个RabbitMQ服务器都能创建虚拟消息服务器,我们称之为虚拟主机。每一个vhost本质上是一个mini版的RabbitMQ服务器,拥有自己的交换机、队列、绑定等,拥有自己的权限机制。vhost之于Rabbit就像虚拟机之于物理机一样。他们通过在各个实例间提供逻辑上分离,允许为不同的应用程序安全保密的运行数据,这很有,它既能将同一个Rabbit的众多客户区分开来,又可以避免队列和交换器的命名冲突。RabbitMQ提供了开箱即用的默认的虚拟主机“/”,如果不需要多个vhost可以直接使用这个默认的vhost,通过使用缺省的guest用户名和guest密码来访问默认的vhost。
vhost之间是相互独立的,这避免了各种命名的冲突,就像App中的沙盒的概念一样,每个沙盒是相互独立的,且只能访问自己的沙盒,以保证非法访问别的沙盒带来的安全隐患。
参数 | 说明 |
---|---|
ha-mode | 同步模式,包括all(所有),exctly(指定节点的数目),nodes(指定具体节点) |
ha-params | 同步模式为exctly时此参数为int类型比如2,在集群中随机抽取2个节点同步消息 |
ha-params | 同步模式为nodes时此参数为数组类型比如["rabbit@rabbitmq1","rabbit@rabbitmq2"],明确指定在这两个节点上同步消息 |
ha-sync-mode | 队列中消息的同步方式,有效值为 automatic 、manual |
automatic | 默认情况下ha-sync-mode取值为manual,镜像队列中的消息不会主动同步到新的slave中,除非显式调用同步命令。当调用同步命令后,队列开始阻塞,无法对其进行其他操作,直到同步完成。 |
manual | 当ha-sync-mode设置为automatic时, 新加入的slave会默认同步己知的镜像队列。由于同步过程的限制,所以不建议对生产环境中正在使用的队列进行操作。 |
6、节点脱离集群
将要移除的节点停机
rabbitmqctl stop
在主节点进行节点的移除
rabbitmqctl -n rabbit@rabbitmq-01 forget_cluster_node rabbit@rabbitmq-03
三、rabbitmq消息追踪
Trace 是Rabbitmq用于记录每一次发送的消息,方便使用Rabbitmq的开发者调试、排错。
1、启动Tracing插件
在RabbitMQ中默认是关闭的,需手动开启。
启动日志插件
rabbitmq-plugins enable rabbitmq_tracing
开启rabbitmq的tracing插件
rabbitmqctl trace_on
添加trace给我们的虚拟主机地址
myhost:rabbitmqctl trace_on -p myhost
开启了插件后,无需重启,rabbitMq管理界面就会出现Tracing项,可新建追踪。
2、新建trace
新建trace时,JSON模式的数据会被Base64加密,不好观察,所以选择Text模式,同时可在Pattern中配置过滤条件
登录rabbitmq控制台
在Admin>Tracing 目录下添加trace追踪文件信息。添加完成后右侧出现相应的追踪信息文件。
3、查看Tracing日志
当在浏览器上直接打开log时会出现汉字乱码
右键下载后通过文本编辑器查看正常
4、常用命令
查看打开的插件
rabbitmq-plugins list
关闭trace功能
rabbitmqctl trace_off
停止tracing
rabbitmq-plugins disable rabbitmq_tracing
四、卸载rabbitmq
卸载前先停止rabbitmq服务
/usr/lib/rabbitmq/bin/rabbitmqctl stop
查看rabbitmq安装的相关列表
yum list | grep rabbitmq
卸载rabbitmq已安装的相关内容
yum -y remove rabbitmq-server.noarch
查看erlang安装的相关列表
yum list | grep erlang
卸载erlang已安装的相关内容
yum -y remove erlang-*
yum remove erlang.x86_64
删除有关的所有文件
rm -rf /usr/lib64/erlang
rm -rf /var/lib/rabbitmq
rm -rf /usr/local/erlang
rm -rf /usr/local/rabbitmq
五、docker部署rabbitmq集群
version: '3'
services:
rabbitmq1:
hostname: rabbitmq1
image: rabbitmq:3.8-management
container_name: rabbitmq1
environment:
- RABBITMQ_ERLANG_COOKIE='rabbitmq_cookie'
- /etc/localtime:/etc/localtime
ports:
- 15672:15672 #客户端连接端口映射
- 5672:5672
- 15692:15692
volumes:
- /data/rabbitmq/rabbitmq1:/var/lib/rabbitmq #数据卷映射
- /data/rabbitmq/log1:/var/log/rabbitmq/log
rabbitmq2:
hostname: rabbitmq2
image: rabbitmq:3.8-management
container_name: rabbitmq2
environment:
- RABBITMQ_ERLANG_COOKIE='rabbitmq_cookie'
- /etc/localtime:/etc/localtime
ports:
- 15673:15672 #客户端连接端口映射
- 5673:5672
- 15693:15692
volumes:
- /data/rabbitmq/rabbitmq2:/var/lib/rabbitmq #数据卷映射
- /data/rabbitmq/log2:/var/log/rabbitmq/log
rabbitmq3:
hostname: rabbitmq3
image: rabbitmq:3.8-management
container_name: rabbitmq3
environment:
- RABBITMQ_ERLANG_COOKIE='rabbitmq_cookie'
- /etc/localtime:/etc/localtime
ports:
- 15674:15672 #客户端连接端口映射
- 5674:5672
- 15694:15692
volumes:
- /data/rabbitmq/rabbitmq3:/var/lib/rabbitmq #数据卷映射
- /data/rabbitmq/log3:/var/log/rabbitmq/log
集群建立脚本
#!/bin/bash
#reset first node
echo "Reset first rabbitmq node."
docker exec rabbitmq1 /bin/bash -c 'rabbitmqctl stop_app'
docker exec rabbitmq3 /bin/bash -c 'rabbitmq-plugins enable rabbitmq_prometheus'
docker exec rabbitmq1 /bin/bash -c 'rabbitmqctl reset'
docker exec rabbitmq1 /bin/bash -c 'rabbitmqctl start_app'
#build cluster
echo "Starting to build rabbitmq cluster with two ram nodes."
docker exec rabbitmq2 /bin/bash -c 'rabbitmqctl stop_app'
docker exec rabbitmq3 /bin/bash -c 'rabbitmq-plugins enable rabbitmq_prometheus'
docker exec rabbitmq2 /bin/bash -c 'rabbitmqctl reset'
docker exec rabbitmq2 /bin/bash -c 'rabbitmqctl join_cluster --ram rabbit@rabbitmq1'
docker exec rabbitmq2 /bin/bash -c 'rabbitmqctl start_app'
docker exec rabbitmq3 /bin/bash -c 'rabbitmqctl stop_app'
docker exec rabbitmq3 /bin/bash -c 'rabbitmq-plugins enable rabbitmq_prometheus'
docker exec rabbitmq3 /bin/bash -c 'rabbitmqctl reset'
docker exec rabbitmq3 /bin/bash -c 'rabbitmqctl join_cluster --ram rabbit@rabbitmq1'
docker exec rabbitmq3 /bin/bash -c 'rabbitmqctl start_app'
#check cluster status
echo "Check cluster status:"
docker exec rabbitmq1 /bin/bash -c 'rabbitmqctl cluster_status'
docker exec rabbitmq2 /bin/bash -c 'rabbitmqctl cluster_status'
docker exec rabbitmq3 /bin/bash -c 'rabbitmqctl cluster_status'
docker exec rabbitmq1 /bin/bash -c 'rabbitmqctl -q set_cluster_name myrabbitmq'
echo "Starting to create user."
docker exec rabbitmq1 /bin/bash -c 'rabbitmqctl add_user admin K2Q6XDeK'
echo "Set tags for new user."
docker exec rabbitmq1 /bin/bash -c 'rabbitmqctl set_user_tags admin administrator'
echo "Grant permissions to new user."
docker exec rabbitmq1 /bin/bash -c "rabbitmqctl set_permissions -p '/' admin '.*' '.*' '.*'"
# 对/节点配置镜像队列,使用全局复制
rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}'
rabbitmqctl set_policy -p prod ha-all "^" '{"ha-mode":"all"}'
# 配置过半(N/2 + 1)复制镜像队列
rabbitmqctl set_policy ha-halfmore "queueA" '{"ha-mode":"exactly", "ha-params":2}'
rabbitmqctl set_policy -p /prod ha-halfmore "queueA" '{"ha-mode":"exactly", "ha-params":2}'
# 指定优先级,数字越大,优先级越高
rabbitmqctl set_policy --priority 1 ha-all "^" '{"ha-mode":"all"}'
rabbitmqctl set_policy -p /prod --priority 1 ha-all "^" '{"ha-mode":"all"}'
六、nginx对rabbitmq进行负载均衡
upstream rabbitmq{
server 192.168.50.134:5672 max_fails=2 fail_timeout=3s weight=2; ##最大失败2次 超时3秒
server 192.168.50.135:5672 max_fails=2 fail_timeout=3s weight=2;
server 192.168.50.136:5672 max_fails=2 fail_timeout=3s weight=2;
}
server {
listen 5678;
server_name 192.168.106.16;
proxy_connect_timeout 1s;
proxy_timeout 3s;
proxy_pass rabbitmq;
}
评论区