RabbitMQ 相关理论部分
集群配置方式
RabbitMQ可以通过三种方法来部署分布式集群系统,分别是:cluster,federation,shovel
- cluster:
- 不支持跨网段,用于同一个网段内的局域网
- 可以随意的动态增加或者减少
- 节点之间需要运行相同版本的RabbitMQ和Erlang
- federation:应用于广域网,允许单台服务器上的交换机或队列接收发布到另一台服务器上交换机或队列的消息,可以是单独机器或集群。federation队列类似于单向点对点连接,消息会在联盟队列之间转发任意次,直到被消费者接受。通常使用federation来连接internet上的中间服务器,用作订阅分发消息或工作队列。
- shovel:连接方式与federation的连接方式类似,但它工作在更低层次。可以应用于广域网。
集群模式
RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端、支持AJAX。用于在分布式系统中存储转发消息。运行模式大概有3种:
1.单一模式:非集群模式,单台。
2.普通模式:RabbitMQ默认的集群模式。对于Queue来说,消息实体只存在于其中一个节点,A、B两个节点仅有相同的元数据,即队列结构。当消息进入A节点的Queue中后,consumer从B节点拉取时,RabbitMQ会临时在A、B间进行消息传输,把A中的消息实体取出并经过B发送给consumer。所以consumer应尽量连接每一个节点,从中取消息。即对于
同一个逻辑队列,要在多个节点建立物理Queue。否则无论consumer连A或B,出口总在A,会产生瓶颈。该模式存在一个问题就是当A节点故障后,B节点无法取到A节点中还未消费的消息实体。如果做了消息持久化,那么得等A节点恢复,然后才可被消费;如果没有持久化会丢失消息。
3.镜像模式:Queue同时存在多个节点,可通过更改模式实现HA高可用该模式解决了上述问题,其实质和普通模式不同之处在于,消息实体会主动在镜像节点间同步,而不是在consumer取数据时临时拉取。该模式带来的副作用就是除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通讯大大消耗掉。
数据存放模式
1.RAM node:内存节点将所有的队列、交换机、绑定、用户、权限和vhost的元数据定义存储在内存中,好处是可以使得像交换机和队列声明等操作更加的快速。
2.Disk node:将元数据存储在磁盘中,单节点系统只允许磁盘类型的节点,防止重启RabbitMQ的时候,丢失系统的配置信息。
提示:RabbitMQ要求在集群中至少有一个磁盘节点,所有其他节点可以是内存节点,当节点加入或者离开集群时,必须要将该变更通知到至少一个磁盘节点。如果集群中唯一的一个磁盘节点崩溃的话,集群仍然可以保持运行,但是无法进行其他操作(增删改查),直到节点恢复。
解决方案:设置两个磁盘节点,至少有一个是可用的,可以保存元数据的更改。
Erlang cookie
Erlang Cookie是保证不同节点可以相互通信的密钥,要保证集群中的不同节点相互通信必须共享相同的Erlang Cookie。具体的目录存放在/var/lib/rabbitmq/.erlang.cookie。
提示:这就要从rabbitmqctl命令的工作原理说起,RabbitMQ底层是通过Erlang架构来实现的,所以rabbitmqctl会启动Erlang节点,并基于Erlang节点来使用Erlang系统连接RabbitMQ节点,在连接过程中需要正确的Erlang Cookie和节点名称,Erlang节点通过交换Erlang Cookie以获得认证。
RabbitMQ 集群安装
通过yum进行安装
yum -y install epel-release
yum -y install erlang
yum -y install rabbitmq-server
提示:在生产环境中,可能有需要扩展rabbitmq规模,所以尽量保存初次安装的RPM包或使用自建yum源安装,因为可能会因为rabbitmq和erlang版本号不一致,导致无法将新的节点添加到集群中。
systemctl start rabbitmq-server
systemctl enable rabbitmq-server.service
rabbitmq-plugins enable rabbitmq_management
配置各节点之间cookie
在rabbitmq-cluster01操作:
cat /var/lib/rabbitmq/.erlang.cookie
scp /var/lib/rabbitmq/.erlang.cookie rabbitmq-cluster02:/var/lib/rabbitmq/.erlang.cookie
scp /var/lib/rabbitmq/.erlang.cookie rabbitmq-cluster03:/var/lib/rabbitmq/.erlang.cookie
chown rabbitmq. /var/lib/rabbitmq/.erlang.cookie
chcon -u system_u /var/lib/rabbitmq/.erlang.cookie
确认cookie是否相同
[root@rabbitmq-cluster01 ~]# cat /var/lib/rabbitmq/.erlang.cookie
QOUOHQDOYKIZKLUVAIOW
[root@rabbitmq-cluster02 ~]# cat /var/lib/rabbitmq/.erlang.cookie
QOUOHQDOYKIZKLUVAIOW
[root@rabbitmq-cluster03 ~]# cat /var/lib/rabbitmq/.erlang.cookie
QOUOHQDOYKIZKLUVAIOW
添加节点
systemctl restart rabbitmq-server ###重启服务;
执行命令
rabbitmqctl stop_app
rabbitmqctl reset ###抱错的时候,可以执行一下;
rabbitmqctl join_cluster rabbit@rabbitmq-cluster01 ###默认是磁盘节点,如果是内存节点的话,需要加--ram参数;
设置镜像策略
[root@rabbitmq-cluster01 ~]# rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all","ha-sync-mode":"automatic"}'
将所有队列设置为镜像队列,即队列会被复制到各个节点,各个节点状态保持一直。
启用RabbitMQ监控插件,cluster搭建起来后若在web管理工具中rabbitmq_management的Overview的Nodes部分看到"Node statistics not available"的信息,说明在该节点上web管理插件还未启用。
[root@rabbitmq-cluster01 ~]# rabbitmq-plugins enable rabbitmq_management
集群配置好后,可以在 RabbitMQ 任意节点上执行下面的命令来查看是否集群配置成功。
RabbitMQ web界面
http://192.168.32.147:15672
默认用户和密码均为guest;
通过ansbile自动化安装:
# 修改inventories/rabbitmq内容为需要部署rabbitmq-server的ip
# 如果是安装集群,需同时更改group_vars/rabbitmq配置
ansible-playbook -i inventories/rabbitmq -t standalone -k --ask-become-pass rabbitmq.yml # standalone安装
ansible-playbook -i inventories/rabbitmq -t cluster -k --ask-become-pass rabbitmq.yml # cluster安装
rabbitmq-server服务默认配置就足够满足绝大多数的使用场景,其中有如下配置需注意:
- rabbitmq-server的配置分为三部分(/etc/rabbitmq/*):
- enabled_plugins:默认开启的插件,当前只启用rabbitmq_management
- rabbitmq.config:服务配置项
- rabbitmq-env.conf:服务环境变量配置
- rabbitmq.config当前配置:
- cluster_nodes:用于集群模式下的节点自动发现
- log_levels:设定服务不同部分的不通log_levels,默认log_levels级别较低,影响问题排查
- vm_memory_high_watermark:用于设定服务默认内存限制阈值,达到此阈值会影响服务新连接的创建,默认0.4,当前使用0.6
常用命令
常用操作命令有两个:rabbitmqctl和rabbitmqadmin,其中:
- rabbitmqctl是随服务安装自带的命令,不需要rabbitmq用户但需要系统sudo权限才能执行,可以进行用户、权限等配置,粒度较粗
- rabbitmqadmin是rabbitmq官方提供的一个python脚本,依赖于rabbitmq management插件,使用rabbitmq账户进行登录并进行管理操作,可以进行队列级别的管理,此脚本提供的管理功能与15672端口提供的web管理服务一样,用ansible-playbook安装的话会自动放置到对应服务器的 /usr/local/sbin/下面,可直接使用
命令参考
操作命令范例
查看当前服务详细信息 sudo rabbitmqctl environment
查看所有 vhost sudo rabbitmqctl list_vhosts
查看一个vhost下面的所有q及消息数量 sudo rabbitmqctl list_queues -p <vhost> sudo rabbitmqctl list_queues -p /order
查看rabbitmq集群状态 sudo rabbitmqctl cluster_status
添加vhost sudo rabbitmqctl add_vhost <vhost> sudo rabbitmqctl add_vhost -p /order
添加用户 sudo rabbitmqctl add_user <username> <password> sudo rabbitmqctl add_user liulei liuleihenshuai
为用户授权 sudo rabbitmqctl set_permissions [-p <vhostpath>] <user> <conf> <write> <read> sudo rabbitmqctl set_permissions -p /order liulei ".*" ".*" ".*"
导出当前配置 rabbitmqadmin -N <node> -u <username> -p <password> export <profile> rabbitmqadmin -N rmq3.car.bj2.yongche.com -u yongche -p adminyongche export rabb.profile
为新服务导入配置 rabbitmqadmin -N <node> -u <username> -p <password> import <profile> rabbitmqadmin -N rmq3.car.bj2.yongche.com -u yongche -p adminyongche import rabb.profile
日常维护范围
如下列表是针对rabbitmq的日常维护需求,从运维角度需要提供的支持,以及对应每种需求的处理思路:
- 新项目新服务部署
- 用ansible部署对应模式的服务即可
- 老项目新服务拆分
- 因为是老项目,所以之前的集群中已存在一套可用的exchange、binding、queus、users、vhosts等等配置迁移到新服务之前,可以先对已有服务的配置进行到处,然后向新服务导入,可以保证项目迁移过程服务始终可用
- Vhost申请、用户授权
- 使用rabbitmqctl命令处理即可
- 异常队列消息清空
- 使用rabbitmqadmin命令purge queue子命令处理
- 服务监控
- 可直接套用zabbix上的YC-RabbitMQ模板,但需注意,监控依赖于登录rabbitmq的management服务(http)进行信息采集,需要在rabbitmq服务中建立zabbix用户,usertag为monitoring,对所有vhost可读
- 手动创建exchanges、queues、bindings
- 当前大部分情况下,rabbitmq采用粗放式授权,应用程序自主创建exchanges、queues、bindings,但经常也会有需要服务上线前通过手工提前创建队列逻辑的情况,虽然rabbitmqadmin命令可以满足所有需求,但配置binding的时候选项很多,可以通过访问服务的15672http端口,通过界面对应的exchanges、queues等标签进行配置
- 有时候提需求的开发对rabbitmq的分发逻辑可能不是特别了解,提出的只是“我想要一个广播队列”这种需求,此时需要与他讨论来确定具体的exchange name 、exchange type、bingding key、queues name等等