8. RabbitMQ 集群

RabbitMQ这款消息队列中间件产品本身是基于Erlang编写,Erlang语言天生具备分布式特性(通过同步Erlang集群各节点的magic cookie来实现)。因此,RabbitMQ天然支持Clustering。这使得RabbitMQ本身不需要像ActiveMQ、Kafka那样通过ZooKeeper分别来实现HA方案和保存集群的元数据。集群是保证可靠性的一种方式,同时可以通过水平扩展以达到增加消息吞吐量能力的目的。

在实际使用过程中多采取多机多实例部署方式,为了便于同学们练习搭建,有时候你不得不在一台机器上去搭建一个rabbitmq集群,本章主要针对单机多实例这种方式来进行开展。

主要参考官方文档:https://www.rabbitmq.com/clustering.html

8.1. 集群搭建

8.1.1. 准备工作

​ 配置的前提是你的rabbitmq可以运行起来,比如"ps aux|grep rabbitmq"你能看到相关进程,又比如运行“rabbitmqctl status”你可以看到类似如下信息,而不报错:

执行"ps aux|grep rabbitmq"结果如下:
在这里插入图片描述
执行“rabbitmqctl status”结果如下:
在这里插入图片描述
注意:确保RabbitMQ可以运行的,确保完成之后,把RabbitMQ停止,后台看不到RabbitMQ的进程

搭建之前一定要把后台的RabbitMQ的进程停止

8.1.2. 单机多实例搭建

目标:完成单机多实例的搭建

情景:假设有两个rabbitmq节点,分别为rabbit-1, rabbit-2,rabbit-1作为主节点,rabbit-2作为从节点。

启动命令:RABBITMQ_NODE_PORT=5672 RABBITMQ_NODENAME=rabbit-1 rabbitmq-server -detached

结束命令:rabbitmqctl -n rabbit-1 stop

集群启动

第一步:启动第一个节点rabbit-1,命令如下:

sudo RABBITMQ_NODE_PORT=5672 RABBITMQ_NODENAME=rabbit-1 rabbitmq-server start &

执行结果如下:

user@Server-node:/$ sudo RABBITMQ_NODE_PORT=5672 RABBITMQ_NODENAME=rabbit-1 rabbitmq-server start
...............省略...................
  ##########  Logs: /var/log/rabbitmq/rabbit-1.log
  ######  ##        /var/log/rabbitmq/rabbit-1-sasl.log
  ##########
              Starting broker...
 completed with 7 plugins.

至此节点rabbit-1启动完成。

第二步:启动第二个节点rabbit-2,命令如下:

user@Server-node:/$ sudo RABBITMQ_NODE_PORT=5673 RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15673}]" RABBITMQ_NODENAME=rabbit-2 rabbitmq-server start & 

注意:web管理插件端口占用,所以还要指定其web插件占用的端口号

RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15673}]"

执行结果如下:

user@Server-node:/$ sudo RABBITMQ_NODE_PORT=5673 RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15673}]" RABBITMQ_NODENAME=rabbit-2 rabbitmq-server start
..............省略..................
  ##########  Logs: /var/log/rabbitmq/rabbit-2.log
  ######  ##        /var/log/rabbitmq/rabbit-2-sasl.log
  ##########
              Starting broker...
 completed with 7 plugins.

至此节点rabbit-2启动完成。

第三步:验证启动 "ps aux|grep rabbitmq”

rabbitmq  2022  2.7  0.4 5349380 77020 ?       Sl   11:03   0:06 /usr/lib/erlang/erts-9.2/bin/beam.smp -W w -A 128 -P 1048576 -t 5000000 -stbt db -zdbbl 128000 -K true -B i -- -root /usr/lib/erlang -progname erl -- -home /var/lib/rabbitmq -- -pa /usr/lib/rabbitmq/lib/rabbitmq_server-3.6.15/ebin -noshell -noinput -s rabbit boot -sname rabbit-1 -boot start_sasl -kernel inet_default_connect_options [{nodelay,true}] -rabbit tcp_listeners [{"auto",5672}] -sasl errlog_type error -sasl sasl_error_logger false -rabbit error_logger {file,"/var/log/rabbitmq/rabbit-1.log"} -rabbit sasl_error_logger {file,"/var/log/rabbitmq/rabbit-1-sasl.log"} -rabbit enabled_plugins_file "/etc/rabbitmq/enabled_plugins" -rabbit plugins_dir "/usr/lib/rabbitmq/plugins:/usr/lib/rabbitmq/lib/rabbitmq_server-3.6.15/plugins" -rabbit plugins_expand_dir "/var/lib/rabbitmq/mnesia/rabbit-1-plugins-expand" -os_mon start_cpu_sup false -os_mon start_disksup false -os_mon start_memsup false -mnesia dir "/var/lib/rabbitmq/mnesia/rabbit-1" -kernel inet_dist_listen_min 25672 -kernel inet_dist_listen_max 25672 start
rabbitmq  2402  4.2  0.4 5352196 77196 ?       Sl   11:05   0:05 /usr/lib/erlang/erts-9.2/bin/beam.smp -W w -A 128 -P 1048576 -t 5000000 -stbt db -zdbbl 128000 -K true -B i -- -root /usr/lib/erlang -progname erl -- -home /var/lib/rabbitmq -- -pa /usr/lib/rabbitmq/lib/rabbitmq_server-3.6.15/ebin -noshell -noinput -s rabbit boot -sname rabbit-2 -boot start_sasl -kernel inet_default_connect_options [{nodelay,true}] -rabbit tcp_listeners [{"auto",5673}] -sasl errlog_type error -sasl sasl_error_logger false -rabbit error_logger {file,"/var/log/rabbitmq/rabbit-2.log"} -rabbit sasl_error_logger {file,"/var/log/rabbitmq/rabbit-2-sasl.log"} -rabbit enabled_plugins_file "/etc/rabbitmq/enabled_plugins" -rabbit plugins_dir "/usr/lib/rabbitmq/plugins:/usr/lib/rabbitmq/lib/rabbitmq_server-3.6.15/plugins" -rabbit plugins_expand_dir "/var/lib/rabbitmq/mnesia/rabbit-2-plugins-expand" -os_mon start_cpu_sup false -os_mon start_disksup false -os_mon start_memsup false -mnesia dir "/var/lib/rabbitmq/mnesia/rabbit-2" -rabbitmq_management listener [{port,15673}] -kernel inet_dist_listen_min 25673 -kernel inet_dist_listen_max 25673 start

第四步:rabbit-1操作作为主节点,命令集如下:

//停止应用
user@Server-node:/$ sudo rabbitmqctl -n rabbit-1 stop_app
Stopping rabbit application on node 'rabbit-1@Server-node'
//目的是清除节点上的历史数据(如果不清除,无法将节点加入到集群)
user@Server-node:/$ sudo rabbitmqctl -n rabbit-1 reset
Resetting node 'rabbit-1@Server-node'
//启动应用
user@Server-node:/$ sudo rabbitmqctl -n rabbit-1 start_app
Starting node 'rabbit-1@Server-node'

第五步:rabbit2操作为从节点,命令集如下:

//停止应用
user@Server-node:/$ sudo rabbitmqctl -n rabbit-2 stop_app
Stopping rabbit application on node 'rabbit-2@Server-node'
//目的是清除节点上的历史数据(如果不清除,无法将节点加入到集群)
user@Server-node:/$ sudo rabbitmqctl -n rabbit-2 reset
Resetting node 'rabbit-2@Server-node'
//将rabbit2节点加入到rabbit1(主节点)集群当中【Server-node服务器的主机名】
user@Server-node:/$ sudo rabbitmqctl -n rabbit-2 join_cluster rabbit-1@'Server-node'
Clustering node 'rabbit-2@Server-node' with 'rabbit-1@Server-node'
//启动应用
user@Server-node:/$ sudo rabbitmqctl -n rabbit-2 start_app
Starting node 'rabbit-2@Server-node'

第六步:验证集群状态

user@Server-node:/$ sudo rabbitmqctl cluster_status -n rabbit-1
Cluster status of node 'rabbit-1@Server-node'
//集群有两个节点:rabbit-1@Server-node、rabbit-2@Server-node
[{nodes,[{disc,['rabbit-1@Server-node','rabbit-2@Server-node']}]},
 {running_nodes,['rabbit-2@Server-node','rabbit-1@Server-node']},
 {cluster_name,<<"rabbit-1@Server-node.localdomain">>},
 {partitions,[]},
 {alarms,[{'rabbit-2@Server-node',[]},{'rabbit-1@Server-node',[]}]}]

第七步:Web监控
在这里插入图片描述
总结:至此单机多实例集群搭建完成

Tips:

​ 如果采用多机部署方式,需读取其中一个节点的cookie, 并复制到其他节点(节点之间通过cookie确定相互是否可通信)。cookie存放在/var/lib/rabbitmq/.erlang.cookie。

例如:主机名分别为rabbit-1、rabbit-2

1、逐个启动各节点

2、配置各节点的hosts文件( vim /etc/hosts)

​ ip1:rabbit-1

​ ip2:rabbit-2

其它步骤雷同单机部署方式

docker部署RabbitMQ集群

一、RabbitMQ集群概念

RabbitMQ 有三种模式:单机模式,普通集群模式,镜像集群模式。单机模式即单独运行一个 rabbitmq 实例,而集群模式需要创建多个 rabbitmq实例。

1、普通集群模式

概念:
默认的集群模式。需要创建多个 RabbitMQ 节点。但对于 Queue 和消息来说,只存在于其中一个节点,其他节点仅同步元数据,即队列的结构信息。
当消息进入Queue后,如果 Consumer 从创建Queue的这个节点消费消息时,可以直接取出来;但如果 consumer 连接的是其他节点,那 rabbitmq 会把 queue 中的消息从创建它的节点中取出并经过连接节点转发后再发送给consumer。
所以 consumer 应尽量连接每一个节点。并针对同一个逻辑队列,要在多个节点建立物理 Queue。否则无论 consumer 连接哪个节点,都会从创建 queue 的节点获取消息,会产生瓶颈。
在这里插入图片描述
特点:
(1)Exchange 的元数据信息在所有节点上是一致的,而 Queue(存放消息的队列)的完整数据则只会存在于创建它的那个节点上。其他节点只知道这个 queue 的 metadata 信息和一个指向 queue 的 owner node 的指针;

(2)RabbitMQ 集群会始终同步四种类型的内部元数据(类似索引):
  a.队列元数据:队列名称和它的属性;
  b.交换器元数据:交换器名称、类型和属性;
  c.绑定元数据:一张简单的表格展示了如何将消息路由到队列;
  d.vhost元数据:为 vhost 内的队列、交换器和绑定提供命名空间和安全属性;
  因此,当用户访问其中任何一个 RabbitMQ 节点时,通过 rabbitmqctl 查询到的元数据信息都是相同的。

(3)无法实现高可用性,当创建 queue 的节点故障后,其他节点是无法取到消息实体的。如果做了消息持久化,那么得等创建 queue 的节点恢复后,才可以被消费。如果没有持久化的话,就会产生消息丢失的现象。

2、镜像集群模式

概念:
把队列做成镜像队列,让各队列存在于多个节点中,属于 RabbitMQ 的高可用性方案。镜像模式和普通模式的不同在于,queue和 message 会在集群各节点之间同步,而不是在 consumer 获取数据时临时拉取。

特点:
(1)实现了高可用性。部分节点挂掉后,不会影响 rabbitmq 的使用。
(2)降低了系统性能。镜像队列数量过多,大量的消息同步也会加大网络带宽开销。
(3)适合对可用性要求较高的业务场景。

二、RabbitMQ普通集群部署

1、拉镜像

#docker pull rabbitmq:management

2、运行容器

~ » docker run -d --hostname rabbit_host1 --name rabbitmq1 -p 15672:15672 -p 5672:5672 -e RABBITMQ_ERLANG_COOKIE='rabbitmq_cookie' rabbitmq:management
cae624491fc50c6e26239473de0b25acd666b095ac642e628ea65e00bdab6bc4  #启动实例1
------------------------------------------------------------
~ » docker run -d --hostname rabbit_host2 --name rabbitmq2 -p 5673:5672 --link rabbitmq1:rabbit_host1 -e RABBITMQ_ERLANG_COOKIE='rabbitmq_cookie' rabbitmq:management
2b43359157e07fe2d6138eeb54384fffec4d40a723175aa36a8403b6fabe33e2  #启动实例2
------------------------------------------------------------
~ » docker run -d --hostname rabbit_host3 --name rabbitmq3 -p 5674:5672 --link rabbitmq1:rabbit_host1 --link rabbitmq2:rabbit_host2 -e RABBITMQ_ERLANG_COOKIE='rabbitmq_cookie' rabbitmq:management
5582f5e1480acfbe209f2b8e887b035a3c6b591e47b48bf5272a4d79deed4699  #启动实例3
------------------------------------------------------------

主要参数:
-p 15672:15672 management 界面管理访问端口
-p 5672:5672 amqp 访问端口
–link 容器之间连接
Erlang Cookie 值必须相同,也就是一个集群内 RABBITMQ_ERLANG_COOKIE 参数的值必须相同。因为 RabbitMQ 是用Erlang实现的,Erlang Cookie 相当于不同节点之间通讯的密钥,Erlang节点通过交换 Erlang Cookie 获得认证。

3、加入节点到集群

设置节点1:

~ » docker exec -it rabbitmq1 bash 
root@rabbit_host1:/# rabbitmqctl stop_app   #停止服务
RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead.
Stopping rabbit application on node rabbit@rabbit_host1 ...
root@rabbit_host1:/# rabbitmqctl reset      #重置服务
RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead.
Resetting node rabbit@rabbit_host1 ...
root@rabbit_host1:/# rabbitmqctl start_app  #启动服务
RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead.
Starting node rabbit@rabbit_host1 ...
root@rabbit_host1:/# exit
exit
------------------------------------------------------------

设置节点2,加入到集群:

~ » docker exec -it rabbitmq2 bash                                                                           kongfanyu@bogon
root@rabbit_host2:/# rabbitmqctl stop_app
RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead.
Stopping rabbit application on node rabbit@rabbit_host2 ...
root@rabbit_host2:/# rabbitmqctl reset
RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead.
Resetting node rabbit@rabbit_host2 ...
root@rabbit_host2:/# rabbitmqctl join_cluster --ram rabbit@rabbit_host1  #加入集群
RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead.
Clustering node rabbit@rabbit_host2 with rabbit@rabbit_host1
root@rabbit_host2:/# rabbitmqctl start_app
RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead.
Starting node rabbit@rabbit_host2 ...
root@rabbit_host2:/# exit
exit
------------------------------------------------------------

设置节点3,加入到集群:

~ » docker exec -it rabbitmq3 bash
root@rabbit_host3:/# rabbitmqctl stop_app
RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead.
Stopping rabbit application on node rabbit@rabbit_host3 ...
root@rabbit_host3:/# rabbitmqctl reset
RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead.
Resetting node rabbit@rabbit_host3 ...
root@rabbit_host3:/# rabbitmqctl join_cluster --ram rabbit@rabbit_host1  #加入集群
RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead.
Clustering node rabbit@rabbit_host3 with rabbit@rabbit_host1
root@rabbit_host3:/# rabbitmqctl start_app
RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead.
Starting node rabbit@rabbit_host3 ...
root@rabbit_host3:/# exit
exit

主要参数:
–ram 表示设置为内存节点,忽略次参数默认为磁盘节点。该配置启动了3个节点,1个磁盘节点和2个内存节点。

设置好之后,使用 http://ip:15672 进行访问,默认账号密码:guest/guest
在这里插入图片描述可以看到,已经有多个节点了。

三、RabbitMQ镜像集群部署

1、策略policy概念

使用RabbitMQ镜像功能,需要基于RabbitMQ策略来实现,策略policy是用来控制和修改群集范围的某个vhost队列行为和Exchange行为。策略policy就是要设置哪些Exchange或者queue的数据需要复制、同步,以及如何复制同步。

为了使队列成为镜像队列,需要创建一个策略来匹配队列,设置策略有两个键“ha-mode和 ha-params(可选)”。ha-params根据ha-mode设置不同的值,下表说明这些key的选项。
在这里插入图片描述
2、添加策略

登录rabbitmq管理页面 ——> Admin ——> Policies ——> Add / update a policy
在这里插入图片描述
name:随便取,策略名称
Pattern:^ 匹配符,只有一个^代表匹配所有
Definition:ha-mode=all 为匹配类型,分为3种模式:all(表示所有的queue)

或者使用命令:
#rabbitmqctl set_policy ha-all “^” ‘{“ha-mode”:“all”}’

3、查看效果

此策略会同步所在同一VHost中的交换器和队列数据。设置好policy之后,使用 http://ip:15672 再次进行访问,可以看到队列镜像同步。
在这里插入图片描述

四、Springboot配置RabbitMQ集群

1、配置RabbitMQ单机

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: username
    password: password

或者使用addresses

spring:
  rabbitmq:
    addresses:ip1:port1
    username: username
    password: password

2、配置RabbitMQ集群

addresses节点用逗号分隔

spring:
  rabbitmq:
    addresses:ip1:port1,ip2:port2,ip3:port3
    username: username
    password: password

8.2. 集群监控

在广大的互联网行业中RabbitMQ几乎都会有集群,那么对于集群的监控就成了企业生态中必不可少的一环。接下来我们来将讲解主要的4种监控。

8.2.1. 管理界面监控

管理界面监控需要我们开启对应的插件(rabbitmq-plugins enable rabbitmq_management)

然后访问http://ip:15672
在这里插入图片描述
在管理控制台我们就可以直观的看到集群中的每一个节点是否正常,如果为红色则表示节点挂掉了,同时可以很方便的查看到各个节点的内存、磁盘等相关的信息,使用起来也是非常方便的。但是遗憾的该功能做的比较简陋,没有告警等一些列的个性化设置,同时如果想把他接入到公司其他的监控系统统一管理也是很难做到的,所以扩展性不强,一般在小型企业的小集群中使用。

8.2.2. tracing日志监控

对于企业级的应用开发来讲,我们通常都会比较关注我们的消息,甚至很多的场景把消息的可靠性放在第一位,但是我们的MQ集群难免会出现消息异常丢失或者客户端无法发送消息等异常情况,此时为了帮助开发人员快速的定位问题,我们就可以对消息的投递和消费过程进行监控,而tracing日志监控插件帮我们很好的实现了该功能,具体的实现参见7.5章节

8.2.3. 定制自己的监控系统

RabbitMQ提供了很丰富的restful风格的api接口,我们可以通过这些接口得到对应的集群数据,此时我们就可以定制我们的监控系统。

HTTP API URLHTTP 请求类型接口含义
/api/connectionsGET获取当前RabbitMQ集群下所有打开的连接
/api/nodesGET获取当前RabbitMQ集群下所有节点实例的状态信息
/api/vhosts/{vhost}/connectionsGET获取某一个虚拟机主机下的所有打开的connection连接
/api/connections/{name}/channelsGET获取某一个连接下所有的管道信息
/api/vhosts/{vhost}/channelsGET获取某一个虚拟机主机下的管道信息
/api/consumers/{vhost}GET获取某一个虚拟机主机下的所有消费者信息
/api/exchanges/{vhost}GET获取某一个虚拟机主机下面的所有交换器信息
/api/queues/{vhost}GET获取某一个虚拟机主机下的所有队列信息
/api/usersGET获取集群中所有的用户信息
/api/users/{name}GET/PUT/DELETE获取/更新/删除指定用户信息
/api/users/{user}/permissionsGET获取当前指定用户的所有权限信息
/api/permissions/{vhost}/{user}GET/PUT/DELETE获取/更新/删除指定虚拟主机下特定用户的权限
/api/exchanges/{vhost}/{name}/publishPOST在指定的虚拟机主机和交换器上发布一个消息
/api/queues/{vhost}/{name}/getPOST在指定虚拟机主机和队列名中获取消息,同时该动作会修改队列状态
/api/healthchecks/node/{node}GET获取指定节点的健康检查状态

更多API的相关信息和描述可以访问http://ip:15672/api/ http://localhost:15672/api/nodes

http://localhost:15672/api/index.html
在这里插入图片描述
接下来我们使用RabbitMQ Http API接口来获取集群监控数据

  1. HttpClient以及Jackson的相关Jar

    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.3.6</version>
    </dependency>
    <dependency>
     <groupId>com.fasterxml.jackson.core</groupId>
     <artifactId>jackson-databind</artifactId>
     <version>2.7.4</version>
    </dependency>
    <dependency>
     <groupId>com.fasterxml.jackson.core</groupId>
     <artifactId>jackson-annotations</artifactId>
     <version>2.7.4</version>
    </dependency>
    <dependency>
     <groupId>com.fasterxml.jackson.core</groupId>
     <artifactId>jackson-core</artifactId>
     <version>2.7.4</version>
    </dependency>
    
  2. 创建MonitorRabbitMQ类实现具体的代码

    package com.ujiuye.rabbitmq;
    
    import com.fasterxml.jackson.databind.DeserializationFeature;
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.apache.http.HttpEntity;
    import org.apache.http.auth.UsernamePasswordCredentials;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.impl.auth.BasicScheme;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.util.EntityUtils;
    
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    /**
     * RabbitMQ的监控
     */
    public class MonitorRabbitMQ {
        //RabbitMQ的HTTP API——获取集群各个实例的状态信息,ip替换为自己部署相应实例的
        private static String RABBIT_NODES_STATUS_REST_URL = "http://192.168.13.111:15672/api/nodes";
        //RabbitMQ的HTTP API——获取集群用户信息,ip替换为自己部署相应实例的
        private static String RABBIT_USERS_REST_URL = "http://192.168.13.111:15672/api/users";
        //rabbitmq的用户名
        private static String RABBIT_USER_NAME = "guest";
        //rabbitmq的密码
        private static String RABBIT_USER_PWD = "guest";
    
        public static void main(String[] args) {
            try {
                //step1.获取rabbitmq集群各个节点实例的状态信息
                Map<String, ClusterStatus> clusterMap =
                        fetchRabbtMQClusterStatus(RABBIT_NODES_STATUS_REST_URL, RABBIT_USER_NAME, RABBIT_USER_PWD);
    
                //step2.打印输出各个节点实例的状态信息
                for (Map.Entry entry : clusterMap.entrySet()) {
                    System.out.println(entry.getKey() + " : " + entry.getValue());
                }
    
                //step3.获取rabbitmq集群用户信息
                Map<String, User> userMap =
                        fetchRabbtMQUsers(RABBIT_USERS_REST_URL, RABBIT_USER_NAME, RABBIT_USER_PWD);
    
                //step4.打印输出rabbitmq集群用户信息
                for (Map.Entry entry : userMap.entrySet()) {
                    System.out.println(entry.getKey() + " : " + entry.getValue());
                }
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public static Map<String, ClusterStatus> fetchRabbtMQClusterStatus(String url, String username, String password) throws IOException {
            Map<String, ClusterStatus> clusterStatusMap = new HashMap<String, ClusterStatus>();
            String nodeData = getData(url, username, password);
            JsonNode jsonNode = null;
            try {
                jsonNode = JsonUtil.toJsonNode(nodeData);
            } catch (IOException e) {
                e.printStackTrace();
            }
            Iterator<JsonNode> iterator = jsonNode.iterator();
            while (iterator.hasNext()) {
                JsonNode next = iterator.next();
                ClusterStatus status = new ClusterStatus();
                status.setDiskFree(next.get("disk_free").asLong());
                status.setFdUsed(next.get("fd_used").asLong());
                status.setMemoryUsed(next.get("mem_used").asLong());
                status.setProcUsed(next.get("proc_used").asLong());
                status.setSocketUsed(next.get("sockets_used").asLong());
                clusterStatusMap.put(next.get("name").asText(), status);
            }
            return clusterStatusMap;
        }public static Map<String, User> fetchRabbtMQUsers(String url, String username, String password) throws IOException {
            Map<String, User> userMap = new HashMap<String, User>();
            String nodeData = getData(url, username, password);
            JsonNode jsonNode = null;
            try {
                jsonNode = JsonUtil.toJsonNode(nodeData);
            } catch (IOException e) {
                e.printStackTrace();
            }
            Iterator<JsonNode> iterator = jsonNode.iterator();
            while (iterator.hasNext()) {
                JsonNode next = iterator.next();
                User user = new User();
                user.setName(next.get("name").asText());
                user.setTags(next.get("tags").asText());
                userMap.put(next.get("name").asText(), user);
            }
            return userMap;
        }
    
        public static String getData(String url, String username, String password) throws IOException {
            CloseableHttpClient httpClient = HttpClients.createDefault();
            UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, password);
            HttpGet httpGet = new HttpGet(url);
            httpGet.addHeader(BasicScheme.authenticate(creds, "UTF-8", false));
            httpGet.setHeader("Content-Type", "application/json");
            CloseableHttpResponse response = httpClient.execute(httpGet);
    
            try {
                if (response.getStatusLine().getStatusCode() != 200) {
                    System.out.println("call http api to get rabbitmq data return code: " + response.getStatusLine().getStatusCode() + ", url: " + url);
                }
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    return EntityUtils.toString(entity);
                }
            } finally {
                response.close();
            }
    
            return null;
        }
    
        public static class JsonUtil {
            private static ObjectMapper objectMapper = new ObjectMapper();
    
            static {
                objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
                //objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
            }
    
            public static JsonNode toJsonNode(String jsonString) throws IOException {
                return objectMapper.readTree(jsonString);
            }
        }
    
        public static class User {
            private String name;
            private String tags;
    
            @Override
            public String toString() {
                return "User{" +
                        "name=" + name +
                        ", tags=" + tags +
                        '}';
            }
            //GET/SET方法省略
    
        }
    
        public static class ClusterStatus {
            private long diskFree;
            private long diskLimit;
            private long fdUsed;
            private long fdTotal;
            private long socketUsed;
            private long socketTotal;
            private long memoryUsed;
            private long memoryLimit;
            private long procUsed;
            private long procTotal;
           //GET/SET方法省略
            @Override
            public String toString() {
                return "ClusterStatus{" +
                        "diskFree=" + diskFree +
                        ", diskLimit=" + diskLimit +
                        ", fdUsed=" + fdUsed +
                        ", fdTotal=" + fdTotal +
                        ", socketUsed=" + socketUsed +
                        ", socketTotal=" + socketTotal +
                        ", memoryUsed=" + memoryUsed +
                        ", memoryLimit=" + memoryLimit +
                        ", procUsed=" + procUsed +
                        ", procTotal=" + procTotal +
                        '}';
            }
        }
    }
    
  3. 启动测试

rabbit@rabbit_host3 : ClusterStatus{diskFree=55469092864, diskLimit=0, fdUsed=97, fdTotal=0, socketUsed=0, socketTotal=0, memoryUsed=110997504, memoryLimit=0, procUsed=554, procTotal=0}
rabbit@rabbit_host2 : ClusterStatus{diskFree=55469092864, diskLimit=0, fdUsed=97, fdTotal=0, socketUsed=0, socketTotal=0, memoryUsed=107008000, memoryLimit=0, procUsed=554, procTotal=0}
rabbit@rabbit_host1 : ClusterStatus{diskFree=55469092864, diskLimit=0, fdUsed=99, fdTotal=0, socketUsed=0, socketTotal=0, memoryUsed=106102784, memoryLimit=0, procUsed=556, procTotal=0}
guest : User{name=guest, tags=administrator}

8.2.4. Zabbix 监控RabbitMQ

Zabbix是一个基于WEB界面提供分布式系统监视以及网络监视功能的企业级开源解决方案,他也可以帮助我们搭建一个MQ集群的监控系统,同时提供预警等功能,但是由于其搭建配置要求比较高一般都是由运维人员负责搭建,感兴趣的同学可以访问https://www.zabbix.com/ 官网进行了解学习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值