rabbitmq3.6.5鏡像集群搭建以及haproxy負載均衡


一、集群架構

后端75、103、69分別是3台rabbitmq節點做鏡像集群,前端103用haproxy作為負載均衡器

二、安裝rabbitmq節點

參照

https://www.cnblogs.com/sky-cheng/p/10709104.html

三、配置hosts文件

vim /etc/hosts

172.28.18.75 zabbix_server
172.28.18.103 node2
172.28.18.69 node3

這里的zabbix_server主機就是node1,因為是我一台監控服務器,所以我就沒有修改主機名。一下zabbix_server主機對應的就是node1節點。

四、設置erlang cookie

RabbitMQ節點之間和命令行工具 (e.g. rabbitmqctl)是使用Cookie互通的,Cookie是一組隨機的數字+字母的字符串。當RabbitMQ服務器啟動的時候,Erlang VM會自動創建一個隨機內容的Cookie文件。如果是通過源安裝RabbitMQ的話,Erlang Cookie 文件在/var/lib/rabbitmq/.erlang.cookie。如果是通過源碼安裝的RabbitMQ,Erlang Cookie文件$HOME/.erlang.cookie。

首先需要將3個節點的cookie進行統一,將75的.erlang.cookie覆蓋到103和69的cookie

.erlang.cookie文件權限默認是400

[root@zabbix_server src]# ll -a /var/lib/rabbitmq/
總用量 16
drwxr-xr-x   3 rabbitmq rabbitmq 4096 3月  29 05:48 .
drwxr-xr-x. 34 root     root     4096 4月  15 10:13 ..
-r--------   1 rabbitmq rabbitmq   20 4月  15 00:00 .erlang.cookie
drwxr-x---   4 rabbitmq rabbitmq 4096 4月  18 09:12 mnesia

修改權限為777

chmod 777 /var/lib/rabbitmq/.erlang.cookie
[root@zabbix_server src]# ll -a /var/lib/rabbitmq/.erlang.cookie
-rwxrwxrwx 1 rabbitmq rabbitmq 20 4月 15 00:00 /var/lib/rabbitmq/.erlang.cookie

復制文件

[root@zabbix_server src]# scp -P25601 /var/lib/rabbitmq/.erlang.cookie root@172.28.18.103:/var/lib/rabbitmq/
root@172.28.18.103's password: 
.erlang.cookie                                                        100%   20     0.0KB/s   00:00  
[root@zabbix_server src]# scp -P25601 /var/lib/rabbitmq/.erlang.cookie root@172.28.18.69:/var/lib/rabbitmq/
root@172.28.18.69's password: 
.erlang.cookie                                                        100%   20     0.0KB/s   00:00 

驗證三個節點文件內容是否相同

[root@zabbix_server src]# cat /var/lib/rabbitmq/.erlang.cookie
ATHUHJDWKYXPPLSHYCED
[root@localhost src]# cat /var/lib/rabbitmq/.erlang.cookie
ATHUHJDWKYXPPLSHYCED
[root@localhost ~]# cat /var/lib/rabbitmq/.erlang.cookie
ATHUHJDWKYXPPLSHYCED

 再將node1、node2、node3將權限恢復為400

[root@zabbix_server src]# chmod 400 /var/lib/rabbitmq/.erlang.cookie
[root@localhost src]# chmod 400 /var/lib/rabbitmq/.erlang.cookie
[root@localhost ~]# chmod 400 /var/lib/rabbitmq/.erlang.cookie

五、使用detached參數,啟動rabbitmq 節點

先停止3個rabbitmq節點

[root@zabbix_server /]# rabbitmqctl stop
Stopping and halting node rabbit@zabbix_server ...
[root@zabbix_server /]# 

注意修改3個服務器的主機名

[root@localhost src]# hostname
localhost.localdomain
[root@localhost src]# hostname node2.jinglong
[root@localhost src]# hostname node2.jinglong

重啟ssh登錄

[root@node2 ~]# hostname
node2.jinglong

顯示@ node2了

 

啟動3個節點 ,帶detached參數

[root@zabbix_server /]# rabbitmq-server -detached
Warning: PID file not written; -detached was passed.

六、查看3個節點狀態

[root@zabbix_server src]# rabbitmqctl cluster_status
Cluster status of node rabbit@zabbix_server ...
[{nodes,[{disc,[rabbit@zabbix_server]}]},
 {running_nodes,[rabbit@zabbix_server]},
 {cluster_name,<<"rabbit@zabbix_server">>},
 {partitions,[]},
 {alarms,[{rabbit@zabbix_server,[]}]}]
[root@node2 ~]# rabbitmqctl  cluster_status
Cluster status of node rabbit@node2 ...
[{nodes,[{disc,[rabbit@node2]}]},
 {running_nodes,[rabbit@node2]},
 {cluster_name,<<"rabbit@node2">>},
 {partitions,[]},
 {alarms,[{rabbit@node2,[]}]}]
[root@node3 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@node3 ...
[{nodes,[{disc,[rabbit@node3]}]},
 {running_nodes,[rabbit@node3]},
 {cluster_name,<<"rabbit@node3">>},
 {partitions,[]},
 {alarms,[{rabbit@node3,[]}]}]

七、將node2、node3節點加入集群

3個節點啟動后,節點和應用同時啟動,應用默認是standalone模式,即單機模式,所以需要先停掉需要加入集群的node2、node3節點的應用,然后將節點進行加入集群設置:

在node2服務器上操作

[root@node2 ~]# rabbitmqctl stop_app
Stopping node rabbit@node2 ...

注意,這里不能使用 rabbitmqctl stop,這樣會將節點也停掉,就不能進行后續節點加入集群操作了,只能使用stop_app參數停掉應用。

將node2加入集群

[root@node2 ~]# rabbitmqctl join_cluster rabbit@zabbix_server
Clustering node rabbit@node2 with rabbit@zabbix_server ...
Error: unable to connect to nodes [rabbit@zabbix_server]: nodedown

DIAGNOSTICS
===========

attempted to contact: [rabbit@zabbix_server]

rabbit@zabbix_server:
  * unable to connect to epmd (port 4369) on zabbix_server: nxdomain (non-existing domain)


current node details:
- node name: 'rabbitmq-cli-76@node2'
- home dir: /var/lib/rabbitmq
- cookie hash: W3bZoV8WKKWsCgfh3FFkzw==

報錯,(non-existing domain),此時排查3台服務器的/etc/hosts文件內容,保證和hostname名稱一致

vim /etc/hosts

172.28.18.75 zabbix_server
172.28.18.103 node2
172.28.18.69 node3

 再次加入集群

[root@node2 ~]# rabbitmqctl join_cluster rabbit@zabbix_server
Clustering node rabbit@node2 with rabbit@zabbix_server ...
[root@node2 ~]# 

 查看集群狀態

[root@node2 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@node2 ...
[{nodes,[{disc,[rabbit@node2,rabbit@zabbix_server]}]},
 {alarms,[{rabbit@zabbix_server,[]}]}]

此時可以看到nodes里已經有2個節點了node2和zabbix_server,說明集群加入成功

在75上查看集群狀態

[root@zabbix_server src]# rabbitmqctl  cluster_status
Cluster status of node rabbit@zabbix_server ...
[{nodes,[{disc,[rabbit@node2,rabbit@zabbix_server]}]},
 {running_nodes,[rabbit@zabbix_server]},
 {cluster_name,<<"rabbit@zabbix_server">>},
 {partitions,[]},
 {alarms,[{rabbit@zabbix_server,[]}]}]

也能看到有2個節點了,我們再把node3節點也加入集群

[root@node3 ~]# rabbitmqctl join_cluster rabbit@zabbix_server
Clustering node rabbit@node3 with rabbit@zabbix_server ...
[root@node3 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@node3 ...
[{nodes,[{disc,[rabbit@node2,rabbit@node3,rabbit@zabbix_server]}]},
 {alarms,[{rabbit@zabbix_server,[]}]}]

此時,可以看到nodes里出現了node3節點,加入集群成功。我們再把node2和node3節點的應用啟動

我們打開75的管控台

此時節點信息里,已經出現了node2和node3,但是目前的狀態的未運行,所以我們需要把node2和node3的應用啟動

 

[root@node2 ~]# rabbitmqctl start_app
Starting node rabbit@node2 ...
[root@node3 ~]# rabbitmqctl start_app
Starting node rabbit@node3 ...

此時刷新75的管控台

集群中的3個節點都已經正常了

修改下集群名稱便於記憶

rabbitmqctl set_cluster_name rabbitmq_cluster

八、配置鏡像隊列

 在任意一個節點執行設置鏡像隊列策略

[root@zabbix_server src]# rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}' 
Setting policy "ha-all" for pattern "^" to "{\"ha-mode\":\"all\"}" with priority "0" ...
[root@zabbix_server src]# 

九、驗證鏡像隊列

在任意一個節點管控台新建一個隊列,新建完畢后,立刻在其余2個節點都可以看到這個隊列

利用java 編寫一個生產者測試客戶端向其中一個節點隊列發送消息,其余2個節點都可以在管控台看到消息的同步

package com.hl95.rabbitmq.demo;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;


public class Producer {
    public static void main(String[]args) throws IOException,TimeoutException{
        ConnectionFactory factory=new ConnectionFactory();
        //配置連接屬性
        factory.setHost("172.28.18.69");
        factory.setPort(5672);
        factory.setVirtualHost("/");
        factory.setUsername("admin");
        factory.setPassword("xxxxxx");
        
        //得到連接
        Connection connection=factory.newConnection();
        //創建通道
        Channel channel=connection.createChannel();
        //聲明(創建)隊列
        String queueName="test001";
        channel.queueDeclare(queueName, true, false, false, null);
        //發送消息
        String message="你好, RabbitMQ";
        for(int i=0;i<200;i++){
            channel.basicPublish("",queueName, null, message.getBytes("UTF-8"));
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        channel.close();
        connection.close();
    }
}

 

 

 

 

 十、在172.28.18.104上安裝haproxy

1、下載

cd /usr/local/src
wget https://github.com/haproxy/haproxy/archive/v1.5-dev20.tar.gz

2、安裝

tar -zxvf v1.5-dev20.tar.gz
cd haproxy-1.5-dev20/
make TARGET=linux26 prefix=/usr/local/haproxy
make install prefix=/usr/local/haproxy

3、新建配置文件

mkdir /etc/haproxy
touch /etc/haproxy/haproxy.conf
vim /etc/haproxy/haproxy.conf
global
  2    log 127.0.0.1 local2
  3    chroot /usr/local/haproxy
  4    pidfile /var/run/haproxy.pid ###haproxy的pid存放路徑,啟動進程的用戶必須有權限訪問此文件
  5    maxconn 65535 ###最大連接數,默認4000
  6    daemon
  7 
  8 defaults
  9    mode tcp
 10    option tcplog
 11    log global
 12    timeout connect 20s
 13    timeout server 60s
 14    timeout client 60s
 15    retries 3
 16 
 17 listen stats
 18    bind 0.0.0.0:8888 #監聽端口
 19    mode http
 20    option httplog
 21    stats refresh 5s #統計頁面自動刷新時間
 22    stats uri /rabbitmq-stats #統計頁面url
 23    stats realm Haproxy Manager #統計頁面密碼框上提示文本
 24    stats auth admin:xxxxxx #統計頁面用戶名和密碼設置
 25    stats hide-version #隱藏統計頁面上HAProxy的版本信息
 26 
 27 listen rabbitmq_cluster
 28    bind 172.28.18.104:5672     #監聽端口
 29    mode tcp
 30    balance roundrobin
 31    server zabbix_server 172.28.18.75:5672 check inter 5000 rise 2 fall 2
 32    server node1         172.28.18.103:5672 check inter 5000 rise 2 fall 2
 33    server node2         172.28.18.69:5672 check inter 5000 rise 2 fall 2

退出保存,並重啟haproxy

[root@localhost haproxy-1.5-dev20]# ps -ef|grep haproxy
root     23157     1  0 08:49 ?        00:00:00 haproxy -f /etc/haproxy/haproxy.conf
root     23446 20907  0 08:59 pts/2    00:00:00 grep haproxy
[root@localhost haproxy-1.5-dev20]# kill -9 23157
[root@localhost haproxy-1.5-dev20]# haproxy -f /etc/haproxy/haproxy.conf 

4、打開管控台

此時顯示3個rabbitmq節點信息

十一、測試集群的負載均衡功能

利用下面java代碼測試負載均衡代理

package com.hl95.rabbitmq.demo;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;


public class Producer {
    public static void main(String[]args) throws IOException,TimeoutException{
        ConnectionFactory factory=new ConnectionFactory();
        //配置連接屬性
        factory.setHost("172.28.18.104");
        factory.setPort(5672);
        factory.setVirtualHost("/");
        factory.setUsername("admin");
        factory.setPassword("xxxxxxxx");
        
        //得到連接
        Connection connection=factory.newConnection();
        //創建通道
        Channel channel=connection.createChannel();
        //聲明(創建)隊列
        String queueName="test001";
        channel.queueDeclare(queueName, true, false, false, null);
        //發送消息
        String message="你好, RabbitMQ";
        for(int i=0;i<200;i++){
            channel.basicPublish("",queueName, null, message.getBytes("UTF-8"));
            try {
                Thread.sleep(500);
                System.out.println("Consumer: "+message+"---"+i);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        channel.close();
        connection.close();
    }
}

此時我們將客戶端連接改為172.28.18.104的前端haproxy負載均衡服務器的IP和端口,測試發送消息,后端集群節點都能同步到消息

首先執行第一次消息投遞,同時觀察104上haproxy管控台后端連接到哪個rabbitmq節點

上圖可以看到第一次消息投遞是被haproxy分配到了node1節點來接收。

繼續第二次消息投遞

 

 上圖可以看到第二次消息投遞是被haproxy分配到了node1節點來接收。

繼續第三次

第三次消息投遞是被haproxy分配到了zabbix_server節點來接收。

繼續第四次

第四次消息投遞是被haproxy重啟分配回了node1節點來接收。驗證了負載均衡是輪詢的策略。

總共進行了4次投遞,每次200個消息,目前隊列里有800條消息待消費,3個節點的管控台隊列消息是一致的,完全復制的

 

 

至此集群搭建和負載均衡策略配置成功。

十二、模擬節點故障處理

 1、假設75節點的掛掉,那么首先利用forget_cluster_node參數,將此節點移除集群

停掉75上的rabbitmq應用

[root@zabbix_server src]# rabbitmqctl stop_app
Stopping node rabbit@zabbix_server ...

此時,rabbitmq管控台顯示node信息中已經沒有rabbit@zabbix_server了

在其他任意節點查看集群狀態

[root@node3 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@node3 ...
[{nodes,[{disc,[rabbit@node2,rabbit@node3,rabbit@zabbix_server]}]},
 {running_nodes,[rabbit@node2,rabbit@node3]},
 {cluster_name,<<"rabbitmq_cluster">>},
 {partitions,[]},
 {alarms,[{rabbit@node2,[]},{rabbit@node3,[]}]}]

顯示集群中還是3個節點,但是running_nodes中只有2個節點,執行

[root@node3 ~]# rabbitmqctl forget_cluster_node rabbit@zabbix_server
Removing node rabbit@zabbix_server from cluster ...
[root@node3 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@node3 ...
[{nodes,[{disc,[rabbit@node2,rabbit@node3]}]},
 {running_nodes,[rabbit@node2,rabbit@node3]},
 {cluster_name,<<"rabbitmq_cluster">>},
 {partitions,[]},
 {alarms,[{rabbit@node2,[]},{rabbit@node3,[]}]}]

移除節點后,再查看集群狀態,此時已經沒有故障節點的信息了,說明我們將故障節點移除集群。

接下來我們重啟75上的rabbitmq,模擬新節點,怎么重新加入集群

啟動時出現以下錯誤:

[root@zabbix_server src]# rabbitmq-server start


BOOT FAILED
===========

Error description:
   {error,{inconsistent_cluster,"Node rabbit@zabbix_server thinks it's clustered with node rabbit@node3, but rabbit@node3 disagrees"}}

Log files (may contain more information):
   /var/log/rabbitmq/rabbit@zabbix_server.log
   /var/log/rabbitmq/rabbit@zabbix_server-sasl.log

Stack trace:
   [{rabbit_mnesia,check_cluster_consistency,0,
                   [{file,"src/rabbit_mnesia.erl"},{line,598}]},
    {rabbit,'-boot/0-fun-0-',0,[{file,"src/rabbit.erl"},{line,275}]},
    {rabbit,start_it,1,[{file,"src/rabbit.erl"},{line,403}]},
    {init,start_it,1,[]},
    {init,start_em,1,[]}]

{"init terminating in do_boot",{error,{inconsistent_cluster,"Node rabbit@zabbix_server thinks it's clustered with node rabbit@node3, but rabbit@node3 disagrees"}}}
/usr/lib/rabbitmq/bin/rabbitmq-server: line 236: 23268 用戶定義信號 2    start_rabbitmq_server "$@"

說明75上還保留集群信息,但實際上75已經被移除集群了,所以出現上述錯誤,解決方法刪除/var/lib/rabbitmq/mnesia/目錄,里面保存有節點的相關信息

[root@zabbix_server rabbitmq]# rm -rf /var/lib/rabbitmq/mnesia/
[root@zabbix_server rabbitmq]# rabbitmq-server -detached
Warning: PID file not written; -detached was passed.
[root@zabbix_server rabbitmq]# rabbitmqctl cluster_status
Cluster status of node rabbit@zabbix_server ...
[{nodes,[{disc,[rabbit@zabbix_server]}]},
 {running_nodes,[rabbit@zabbix_server]},
 {cluster_name,<<"rabbit@zabbix_server">>},
 {partitions,[]},
 {alarms,[{rabbit@zabbix_server,[]}]}]

刪除后,再重新啟動,查看集群狀態,75已經是初始化狀態,此時是單機模式。接下來加入集群操作:

[root@zabbix_server rabbitmq]# rabbitmqctl join_cluster rabbit@node2 --ram
Clustering node rabbit@zabbix_server with rabbit@node2 ...
[root@zabbix_server rabbitmq]# rabbitmqctl cluster_status
Cluster status of node rabbit@zabbix_server ...
[{nodes,[{disc,[rabbit@node2,rabbit@node3]},{ram,[rabbit@zabbix_server]}]},
 {alarms,[{rabbit@node2,[]},{rabbit@node3,[]}]}]

加入成功,查看集群狀態,已經成功了,此時在另外兩個節點任意一個管控台上觀察節點信息

 

狀態是未運行,在75上啟動應用

[root@zabbix_server rabbitmq]# rabbitmqctl start_app
Starting node rabbit@zabbix_server ...

打開75上的管控台登錄

此時,75節點正常運行,並且是內存模式。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM