准备工作
安装docker:yum install -y docker
docker镜像加速:
{
“registry-mirrors”: [“https://rfwmrno9.mirror.aliyuncs.com”]
}
重载配置文件:sudo systemctl daemon-reload
配置docker开机启动:systemctl enable docker.service
启动docker:systemctl start docker.service
安装docker-compose:
sudo curl -L https://get.daocloud.io/docker/compose/releases/download/1.28.6/docker-compose-uname -s
-uname -m
-o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
创建rabbitmq专用的网卡:
docker network create --driver=bridge --subnet=172.*.0.(1|2)/16 rabbitmqnet
具体IP地址在使用ifconfig查看现有的IP情况后确定。
rabbitMQ的分布式部署方式:
cluster方式:只能用于同一个网段的局域网,节点需要使用相同版本的rabbitMQ和Erlang。
另外还有Federation和Shovel方式。
cluster的节点类型:
磁盘节点:将配置信息和元数据(队列的数据、结构,交换机的名称、属性等等)保存在磁盘中。
内存节点:将配置信息和元数据保存在内存中,消息、队列索引等仍然保存在磁盘中。性能高于磁盘节点,但宕机或崩溃之后会丢失所有数据。
两种类型的节点可以互相转换,即一个节点可以由磁盘类型转换为内存类型,反之亦然。
单节点系统只能是磁盘类型。在多节点的集群中要至少有一个节点是磁盘类型,如果集群中唯一的一个磁盘节点崩溃,集群仍然可以保持运行,但是无法进行其他操作(增删改查),直到节点恢复。
集群节点之间同步的数据和不同步的数据:
1.队列的元数据:队列名称、属性、结构、队列的owner node等
2.交换机的元数据:交换机的名称、类型和属性
3.绑定的元数据:队列和交换机的绑定关系,一张表格展示了如果将消息路由到队列
4.vhost的元数据:其中的队列、交换机和绑定的命名空间和安全属性
不同节点之间只会同步一些元数据,不会同步队列的内容数据。一方面不会因为成倍占用存储空间内而影响消息积压能力;另一方不会因为消息的同步尤其是持久化同步而影响性能。
镜像队列:
1.常规队列的消息仅在队列所属的节点上保存,如果该节点失效则节点上的所有队列所持有的消息都不可用。
2.镜像队列,除了Basic.Publish操作之外,无论在集群中的哪个节点上对队列的消息做读写操作,消息都会被保存到队列所属的节点上(master节点)或从master节点上获取。
3.如果操作发生的节点不是队列的master节点,那么该节点仅仅起到路由的作用,把操作转发给master节点。
4.master节点对消息进行处理的同时会把处理操作通过GM发送给各个slave节点,slave节点收到消息后通过回调交给本节点上的镜像队列进行处理,保证了master和slave节点上的队列内容的一致。
5.master节点宕机之后,选一个slave节点作为master节点。会选择一个最老的slave作为队列的master,因为最老的slave和之前的master之间的同步最完全。如果没有任何一个slave与master完全同步,那么之前的master中没有同步的消息会丢失。
6.新节点加入集群后,其中的队列如果适用镜像队列策略,默认情况下镜像队列中的数据不会同步到新节点,默认配置是ha-synv-mode=manual,可以人工调用同步命令进行同步,同步时镜像队列会阻塞,无法对其进行操作,直到同步完成。配置ha-sync-mode=aotumatic会自动同步,生产环境不推荐。
7.因为队列的元数据在集群的节点之间同步,所以在集群的各节点上都可以看到集群中的所有队列。
master节点的确定方式:
主副本(也叫队列领导者,即master)采用不同的策略在节点之间均匀分配。有以下策略:
1.min-masters:选择承载领导者数量最少的节点
2.client-local:选择声明队列时所在的节点
3.random:随机
搭建集群的前置条件:
1.各个节点的hostname互相可以ping通
2.rabbitMQ使用的端口都可以访问,如5672,5671,15672等。telnet ip [5672|15672|25672]
docker-compose文件:
节点1的内容:
version: ‘3.8’
networks:
rabbit:
external:
name: rabbitmqnet
services:
rabbitmq1:
image: rabbitmq:3.8.3-management
container_name: rabbitmq1
restart: always
hostname: rabbitmq1
ports:
version: ‘3.8’
networks:
rabbit:
external:
name: rabbitmqnet
services:
rabbitmq2:
image: rabbitmq:3.8.3-management
container_name: rabbitmq2
restart: always
hostname: rabbitmq2
mem_limit: 200m
ports:
节点3的内容:
version: ‘3.8’
networks:
rabbit:
external:
name: rabbitmqnet
services:
rabbitmq3:
image: rabbitmq:3.8.3-management
container_name: rabbitmq3
restart: always
hostname: rabbitmq3
mem_limit: 200m
ports:
shell文件:
在winows中创建的sh文件无法在Linux中正常使用,使用vim直接在Linux创建。
主节点:
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
disk节点:
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster rabbitmq1@rabbitmq1 # rabbitmqctl [-n nodename] join_cluster {cluster_node} [–ram]
rabbitmqctl start_app
ram节点:
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster --ram rabbitmq1@rabbitmq1
rabbitmqctl start_app
集群的名称默认是主节点创建的集群名称(rabbitmq1@rabbitmq1),在主节点查看集群名称:rabbitmqctl cluster_status,其中的Cluster name: rabbitmq1@rabbitmq1
如果自定义集群名称,需要在宿主机的hosts文件中做解析。
创建并在后台启动容器:
docker-compose -f rabbitmq-node1.yml up -d
docker-compose -f rabbitmq-node2.yml up -d
docker-compose -f rabbitmq-node3.yml up -d
先进入主节点然后依次进入其他各节点的容器执行shell文件完成集群连接:
docker exec -it rabbitmq1 bash
chmod +x /home/rabbitmq-disk-master.sh
./home/rabbitmq-disk-master.sh
rabbitmqctl cluster_status # 查看当前节点的集群状态
负载均衡:
方式1:HAProxy+Keepalived实现负载均衡和故障转移。
1.HAProxy对rabbitMQ集群中节点实现负载均衡,对节点做健康检测并剔除不在线的节点或自动加入重新上线的节点。一般在每个服务节点上安装HAproxy,每个HAProxy对本节点和所有其他节点做负载均衡。
2.Keepalived为集群提供一个统一的访问地址,和HAProxy一样,都是在每个服务节点安装一个Keepalived服务。
3.Keepalived定时对HAProxy做健康检测,如果HAProxy不在线则关闭掉当前节点的Keepalived服务,并降低优先级。
4.一般通过优先级在众多Keepalived服务之间确定出一个主Keepalived,虚拟IP会被绑定到主Keepalived所在的节点。Keepalived之间通过多播方式发送VRRP广播包,当主Keepalived服务不可用时,备份Keepalived服务收不到这个广播通知,会从中选出一个作为主Keepalived,虚拟IP会漂移到这个新主要Keepalived所在的节点。
5.云服务器使用弹性IP作为虚拟IP。在云服务器中,弹性IP的价格和SLB产品的价格差别不大。
架构图大致如下:
方式2:使用NGINX的stream模块的TCP负载均衡(也叫四层负载均衡)对rabbitMQ集群做负载均衡。本次采用的方式,配置成功后可以访问rabbitMQ的管理后台同时也可以访问5672端口:
http://IP地址:15672/
1.可以对每个节点设置权重(weight)、最大失败次数(max_fails)、每次失败后的暂停时间也叫熔断时间(fail_timeout)、最大连接数(max_conns)、是否是备份节点(backup)等。
2.NGINX通过负载均衡策略选择集群中的一个节点提供服务,如果连接被拒绝或者连接超时(proxy_connect_timeout),则认为该节点无效,会选择另外的节点提供服务。连接失败的信息会被记录到错误日志,如果一个节点的失败次数超出限制(max_fails),NGINX会踢掉该节点,然后在一段时间后(默认60秒)会尝试重新连接该节点,如果恢复则重新加入该节点。
3.负载均衡策略:
轮询:默认
least_conn:最少连接,把请求转发给连接数少的节点
least_time:最低的平均时延,根据规则(connect | first_byte | last_byte)计算服务器的最低平均时延,有限把请求转发给时延低的节点。同时要考虑权重值
hash $remote_addr consistent:使用客户端IP对节点数量做hash,同一个客户端请求会被发送给相同的节点处理
weight:基于权重,值越大权重越高,优先把请求转发给权重高的节点
架构图大致如下:
NGINX负载均衡的配置:
stream {
log_format rabbitmq_cluster ' r e m o t e a d d r [ remote_addr [ remoteaddr[time_local] ’
‘$protocol $status $bytes_sent KaTeX parse error: Double superscript at position 18: …tes_received ' '̲session_time “KaTeX parse error: Double superscript at position 18: …stream_addr" ' '̲"upstream_bytes_sent” “ u p s t r e a m b y t e s r e c e i v e d " " upstream_bytes_received" " upstreambytesreceived""upstream_connect_time”’;
access_log /var/log/nginx/rabbitmq-access.log rabbitmq_cluster;
open_log_file_cache off;
upstream rabbitmq_cluster_management {
least_conn;
server 127.0.0.1:56715 max_fails=3 fail_timeout=60s;
server 127.0.0.1:56725 max_fails=3 fail_timeout=60s;
server 127.0.0.1:56735 max_fails=3 fail_timeout=60s;
}
upstream rabbitmq_cluster_queue {
least_conn;
server 127.0.0.1:56714 max_fails=3 fail_timeout=60s;
server 127.0.0.1:56724 max_fails=3 fail_timeout=60s;
server 127.0.0.1:56734 max_fails=3 fail_timeout=60s;
}
server {
listen 15672;
proxy_connect_timeout 5s; # 与被代理服务器建立连接的超时时间为5s
proxy_timeout 10s; # 获取被代理服务器的响应最大超时时间
proxy_socket_keepalive on; # 开启SO_KEEPALIVE选项进行心跳检测
proxy_next_upstream_tries 3; # 转发请求尝试最多3次
proxy_pass rabbitmq_cluster_management;
}
server {
listen 5672;
proxy_connect_timeout 5s; # 与被代理服务器建立连接的超时时间为5s
proxy_timeout 10s; # 获取被代理服务器的响应最大超时时间
proxy_socket_keepalive on; # 开启SO_KEEPALIVE选项进行心跳检测
proxy_next_upstream_tries 3; # 转发请求尝试最多3次
proxy_pass rabbitmq_cluster_queue;
}
}
方式3:直接使用云厂商提供的付费SLB服务。
配置镜像队列:
方式1:
进入集群中的任意一个节点,执行如下命令声明一个镜像队列的策略:
rabbitmqctl set_policy ha-all “^” ‘{“ha-mode”:“all”}’
rabbitmqctl set_policy ha-mirror_queue “^mirror_q” ‘{“ha-mode”:“all”}’ # 只匹配mirror_q开头的队列
方式2:在rabbitMQ的管理界面添加策略
测试策略:
在程序中或rabbitMQ的管理界面创建队列,会按照匹配规则自动使用相应的策略。查看集群中的队列:rabbitmqctl list_queues
测试镜像队列:
1.查看队列的同步情况:rabbitmqctl list_queues name pid messages slave_pids synchronised_slave_pids
2.把一个队列的master节点停机:rabbitmqctl stop_app,然后再查看队列的同步情况,其中pid是队列的master节点
在项目中测试:
1.配置rabbitmq作为celery的broker
2.在不同节点上创建队列并执行celery任务,查看是否能够正常使用,查看队列的同步情况
3.只保留一个disk节点查看是否能正常执行任务
4.停机所有disk查看是否能正常执行任务
资源限制(警报器):
内存限制:在节点上通过rabbitmqctl status命令查看,其中的Memory
当RabbitMQ服务器使用超出内存限制时,它会引起一个内存报警并且阻塞所有连接。内存报警清除后会恢复正常服务。有以下几种设置方式:
1.在docker-compose文件中设置为环境变量:百分比形式,占用宿主机内容的最大百分比
environment:
磁盘可用空间阈值:在节点上通过rabbitmqctl status命令查看,其中的Free Disk Space
当磁盘空间低于配置(disk_free_limit)的限制时(默认disk_free_limit.absolute=50MB),将触发警报,并阻塞所有生产者。目的是避免填充整个磁盘,否则将导致节点上的所有写操作失败,并可能导致RabbitMQ终止。有以下几种设置方式:
1.在docker-compose文件中设置为环境变量:
volumes:
安全问题:
1.不再使用默认端口;服务器只开启5672和15672端口,前者是由不带TLS的AMQP0-9-1客户端使用,生产或消费消息;后者是管理后台的端口,在有必要的情况下开通5671,由带TLS的AMQP1.0客户端使用。
2.更改默认管理员账号
列出所有用户:rabbitmqctl list_users
修改密码:rabbitmqctl change_password 用户名 新密码
新建用户:rabbitmqctl add_user rmqroot ***
把用户设置为管理员:rabbitmqctl set_user_tags rmqroot administrator
设置访问权限:rabbitmqctl set_permissions -p / rmqroot “.” “.” “.*”
删除旧用户:rabbitmqctl delete_user temp
列出用户的权限:rabbitmqctl list_user_permissions 用户名
节点重新加入到集群:
节点掉线后,集群中的其他节点仍然会把该节点识别为集群成员,但节点本身的识别是已经离开了集群,由于这个差异,在重新上线加入集群时会失败。处理方式:
1.在任意其他成员节点上移除该节点:rabbitmqctl forget_cluster_node node_name
2.在本节点上做加入集群的操作:rabbitmqctl join_cluster cluster_name
rabbitMQ集群的官方文档:https://www.rabbitmq.com/clustering.html
参考推荐:
HAProxy+Keepalived:
https://cloud.tencent.com/developer/article/1026385
NGINX负载均衡:
https://cloud.tencent.com/developer/article/1348407
http://www.weixueyuan.net/a/790.html
rabbitMQ集群:
https://www.rabbitmq.com/clustering.html
https://www.cnblogs.com/Neeo/articles/13915836.html
https://cloud.tencent.com/developer/article/1578678
https://www.cnblogs.com/sgh1023/p/11296013.html
资源限制:
https://www.rabbitmq.com/memory.html
https://www.rabbitmq.com/disk-alarms.html
https://blog.csdn.net/qq_33814088/article/details/83543051
rabbitmq的docker-compose文件:
http://blog.itpub.net/69955379/viewspace-2737775/