搭建 RabbitMQ Server 高可用集群


閱讀目錄:

  • 准備工作
  • 搭建 RabbitMQ Server 單機版
  • RabbitMQ Server 高可用集群相關概念
  • 搭建 RabbitMQ Server 高可用集群
  • 搭建 HAProxy 負載均衡

因為公司測試服務器暫不能用,只能在自己電腦上重新搭建一下 RabbitMQ Server 高可用集群,正好把這個過程記錄下來,以便日后查看。

公司測試服務器上的 RabbitMQ 集群,我搭建的是三台服務器,因為自己電腦空間有限,這邊只能搭建兩台服務器用作高可用集群,用的是 Vagrant 虛擬機管理工具。

環境介紹:

| RabbitMQ | 節點 | IP 地址 | 工作模式 | 操作系統 |
|-----------------|------------|----------|----------|
| node1 | 192.168.1.50 | DISK | CentOS 7.0 - 64位 |
| node2 | 192.168.1.51 | DISK | CentOS 7.0 - 64位 |

整體架構:

1. 准備工作

首先,在node1服務器上,修改vi /etc/hostname

node1

node2服務器上,修改vi /etc/hostname

node2

然后在node1服務器上,修改vi /etc/hosts

node1 192.168.1.50
node2 192.168.1.51
127.0.0.1   node1
::1         node1

node2服務器上,修改vi /etc/hosts

192.168.1.50 node1
192.168.1.51 node2
127.0.0.1   node2
::1         node2

然后查看下hostnamectl status,如果不正確的話,需要再進行設置下:

[root@node1 ~]# hostnamectl status
   Static hostname: node1
         Icon name: computer-vm
           Chassis: vm
        Machine ID: 241163503ce842c489360d0a48a606fc
           Boot ID: cdb59c025cb447e3afed7317af78979e
    Virtualization: oracle
  Operating System: CentOS Linux 7 (Core)
       CPE OS Name: cpe:/o:centos:centos:7
            Kernel: Linux 3.10.0-229.el7.x86_64
      Architecture: x86_64
[root@node1 ~]# hostnamectl --static set-hostname node1

為了后面我們安裝的順利,我們最好再配置一下代理:

[root@node1 ~]# export http_proxy=http://192.168.1.44:1087;export https_proxy=http://192.168.1.44:1087;
[root@node1 ~]# curl ip.cn
當前 IP:104.245.13.31 來自:美國 Linost

2. 搭建 RabbitMQ Server 單機版

下面以node1服務器做演示示例。

首先,更新軟件包和存儲庫:

[root@node1 ~]# yum -y update

然后安裝 Erlang(RabbitMQ 運行需要 Erlang 環境):

[root@node1 ~]# vi /etc/yum.repos.d/rabbitmq-erlang.repo
[root@node1 ~]# [rabbitmq-erlang]
name=rabbitmq-erlang
baseurl=https://dl.bintray.com/rabbitmq/rpm/erlang/20/el/7
gpgcheck=1
gpgkey=https://dl.bintray.com/rabbitmq/Keys/rabbitmq-release-signing-key.asc
repo_gpgcheck=0
enabled=1

[root@node1 ~]# yum -y install erlang socat

然后安裝 RabbitMQ Server:

[root@node1 ~]# mkdir -p ~/download && cd ~/download
[root@node1 download]# wget https://www.rabbitmq.com/releases/rabbitmq-server/v3.6.10/rabbitmq-server-3.6.10-1.el7.noarch.rpm
[root@node1 download]# rpm --import https://www.rabbitmq.com/rabbitmq-release-signing-key.asc
[root@node1 download]# rpm -Uvh rabbitmq-server-3.6.10-1.el7.noarch.rpm

卸載 RabbitMQ 命令:

[root@node1 ~]# rpm -e rabbitmq-server-3.6.10-1.el7.noarch
[root@node1 ~]# rm -rf /var/lib/rabbitmq/     //清除rabbitmq配置文件

安裝好之后,就可以啟動 RabbitMQ Server 了:

[root@node1 download]# systemctl start rabbitmq-server

也可以添加到系統服務中啟動:

[root@node1 download]# systemctl enable rabbitmq-server
Created symlink from /etc/systemd/system/multi-user.target.wants/rabbitmq-server.service to /usr/lib/systemd/system/rabbitmq-server.service.

啟動成功之后,我們可以查看下 RabbitMQ Server 的狀態:

[root@node1 download]# systemctl status rabbitmq-server
● rabbitmq-server.service - RabbitMQ broker
   Loaded: loaded (/usr/lib/systemd/system/rabbitmq-server.service; disabled)
   Active: active (running) since 五 2018-04-27 04:44:31 CEST; 3min 27s ago
  Process: 17216 ExecStop=/usr/sbin/rabbitmqctl stop (code=exited, status=0/SUCCESS)
 Main PID: 17368 (beam.smp)
   Status: "Initialized"
   CGroup: /system.slice/rabbitmq-server.service
           ├─17368 /usr/lib64/erlang/erts-9.3/bin/beam.smp -W w -A 64 -P 1048576 -t 5000000 -stbt db -zdbbl 32000 -K true -- -root /usr/lib64/erlang -progname erl -- -home /var/lib/rabbitmq -- -pa /usr...
           ├─17521 /usr/lib64/erlang/erts-9.3/bin/epmd -daemon
           ├─17655 erl_child_setup 1024
           ├─17675 inet_gethost 4
           └─17676 inet_gethost 4

4月 27 04:44:30 node1 rabbitmq-server[17368]: RabbitMQ 3.6.10. Copyright (C) 2007-2017 Pivotal Software, Inc.
4月 27 04:44:30 node1 rabbitmq-server[17368]: ##  ##      Licensed under the MPL.  See http://www.rabbitmq.com/
4月 27 04:44:30 node1 rabbitmq-server[17368]: ##  ##
4月 27 04:44:30 node1 rabbitmq-server[17368]: ##########  Logs: /var/log/rabbitmq/rabbit@node1.log
4月 27 04:44:30 node1 rabbitmq-server[17368]: ######  ##        /var/log/rabbitmq/rabbit@node1-sasl.log
4月 27 04:44:30 node1 rabbitmq-server[17368]: ##########
4月 27 04:44:30 node1 rabbitmq-server[17368]: Starting broker...
4月 27 04:44:31 node1 rabbitmq-server[17368]: systemd unit for activation check: "rabbitmq-server.service"
4月 27 04:44:31 node1 systemd[1]: Started RabbitMQ broker.
4月 27 04:44:31 node1 rabbitmq-server[17368]: completed with 0 plugins.
[root@node1 download]# systemctl enable rabbitmq-server
ln -s '/usr/lib/systemd/system/rabbitmq-server.service' '/etc/systemd/system/multi-user.target.wants/rabbitmq-server.service'

然后啟動 RabbitMQ Web 管理控制台:

[root@node1 download]# rabbitmq-plugins enable rabbitmq_management
The following plugins have been enabled:
  amqp_client
  cowlib
  cowboy
  rabbitmq_web_dispatch
  rabbitmq_management_agent
  rabbitmq_management

Applying plugin configuration to rabbit@node1... started 6 plugins.

RabbitMQ Server 默認guest用戶,只能localhost地址訪問,我們還需要創建管理用戶:

[root@node1 download]# rabbitmqctl add_user admin admin123 && 
rabbitmqctl set_user_tags admin administrator && 
rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"

然后添加防火牆運行訪問的端口:

[root@node1 download]# firewall-cmd --zone=public --permanent --add-port=4369/tcp && 
firewall-cmd --zone=public --permanent --add-port=25672/tcp && 
firewall-cmd --zone=public --permanent --add-port=5671-5672/tcp && 
firewall-cmd --zone=public --permanent --add-port=15672/tcp && 
firewall-cmd --zone=public --permanent --add-port=61613-61614/tcp && 
firewall-cmd --zone=public --permanent --add-port=1883/tcp && 
firewall-cmd --zone=public --permanent --add-port=8883/tcp
success

重新啟動防火牆:

[root@node1 download]# firewall-cmd --reload
success

上面這些做完了,RabbitMQ 單機版的部署也完成了,我們可以瀏覽器訪問``:

將上面的搭建過程,在node2服務器上,再做重復一邊。

3. RabbitMQ Server 高可用集群相關概念

設計集群的目的

  • 允許消費者和生產者在 RabbitMQ 節點崩潰的情況下繼續運行。
  • 通過增加更多的節點來擴展消息通信的吞吐量。

集群配置方式

  • cluster:不支持跨網段,用於同一個網段內的局域網;可以隨意的動態增加或者減少;節點之間需要運行相同版本的 RabbitMQ 和 Erlang。
  • federation:應用於廣域網,允許單台服務器上的交換機或隊列接收發布到另一台服務器上交換機或隊列的消息,可以是單獨機器或集群。federation 隊列類似於單向點對點連接,消息會在聯盟隊列之間轉發任意次,直到被消費者接受。通常使用 federation 來連接 internet 上的中間服務器,用作訂閱分發消息或工作隊列。
  • shovel:連接方式與 federation 的連接方式類似,但它工作在更低層次。可以應用於廣域網。

節點類型

  • RAM node:內存節點將所有的隊列、交換機、綁定、用戶、權限和 vhost 的元數據定義存儲在內存中,好處是可以使得像交換機和隊列聲明等操作更加的快速。
  • Disk node:將元數據存儲在磁盤中,單節點系統只允許磁盤類型的節點,防止重啟 RabbitMQ 的時候,丟失系統的配置信息。

問題說明:RabbitMQ 要求在集群中至少有一個磁盤節點,所有其他節點可以是內存節點,當節點加入或者離開集群時,必須要將該變更通知到至少一個磁盤節點。如果集群中唯一的一個磁盤節點崩潰的話,集群仍然可以保持運行,但是無法進行其他操作(增刪改查),直到節點恢復。
解決方案:設置兩個磁盤節點,至少有一個是可用的,可以保存元數據的更改。

Erlang Cookie 是保證不同節點可以相互通信的密鑰,要保證集群中的不同節點相互通信必須共享相同的 Erlang Cookie。具體的目錄存放在/var/lib/rabbitmq/.erlang.cookie

說明:這就要從 rabbitmqctl 命令的工作原理說起,RabbitMQ 底層是通過 Erlang 架構來實現的,所以 rabbitmqctl 會啟動 Erlang 節點,並基於 Erlang 節點來使用 Erlang 系統連接 RabbitMQ 節點,在連接過程中需要正確的 Erlang Cookie 和節點名稱,Erlang 節點通過交換 Erlang Cookie 以獲得認證。

鏡像隊列

RabbitMQ 的 Cluster 集群模式一般分為兩種,普通模式和鏡像模式。

  • 普通模式:默認的集群模式,以兩個節點(rabbit01、rabbit02)為例來進行說明。對於 Queue 來說,消息實體只存在於其中一個節點 rabbit01(或者 rabbit02),rabbit01 和 rabbit02 兩個節點僅有相同的元數據,即隊列的結構。當消息進入 rabbit01 節點的 Queue 后,consumer 從 rabbit02 節點消費時,RabbitMQ 會臨時在 rabbit01、rabbit02 間進行消息傳輸,把 A 中的消息實體取出並經過 B 發送給 consumer。所以 consumer 應盡量連接每一個節點,從中取消息。即對於同一個邏輯隊列,要在多個節點建立物理 Queue。否則無論 consumer 連 rabbit01 或 rabbit02,出口總在 rabbit01,會產生瓶頸。當 rabbit01 節點故障后,rabbit02 節點無法取到 rabbit01 節點中還未消費的消息實體。如果做了消息持久化,那么得等 rabbit01 節點恢復,然后才可被消費;如果沒有持久化的話,就會產生消息丟失的現象。
  • 鏡像模式:將需要消費的隊列變為鏡像隊列,存在於多個節點,這樣就可以實現 RabbitMQ 的 HA 高可用性。作用就是消息實體會主動在鏡像節點之間實現同步,而不是像普通模式那樣,在 consumer 消費數據時臨時讀取。缺點就是,集群內部的同步通訊會占用大量的網絡帶寬。

鏡像隊列實現了 RabbitMQ 的高可用性(HA),具體的實現策略如下所示:

ha-mode ha-params 功能
all 鏡像隊列將會在整個集群中復制。當一個新的節點加入后,也會在這 個節點上復制一份。
exactly count 鏡像隊列將會在集群上復制 count 份。如果集群數量少於 count 時候,隊列會復制到所有節點上。如果大於 Count 集群,有一個節點 crash 后,新進入節點也不會做新的鏡像。
nodes node name 鏡像隊列會在 node name 中復制。如果這個名稱不是集群中的一個,這不會觸發錯誤。如果在這個 node list 中沒有一個節點在線,那么這個 queue 會被聲明在 client 連接的節點。

實例列舉:

queue_args("x-ha-policy":"all") //定義字典來設置額外的隊列聲明參數
channel.queue_declare(queue="hello-queue",argument=queue_args)

如果需要設定特定的節點(以rabbit@localhost為例),再添加一個參數:

queue_args("x-ha-policy":"nodes",
           "x-ha-policy-params":["rabbit@localhost"])
channel.queue_declare(queue="hello-queue",argument=queue_args)

可以通過命令行查看那個主節點進行了同步:

$ rabbitmqctl list_queue name slave_pids synchronised_slave_pids

以上內容主要參考:RabbitMQ 分布式集群架構

4. 搭建 RabbitMQ Server 高可用集群

理解了上面的概念之后,我們再搭建 RabbitMQ Server 高可用集群,就非常容易了。

默認.erlang.cookie文件是隱藏的,ls命令並不能查看,你也可以手動搜索下文件:

[root@node1 ~]# find / -name ".erlang.cookie"
/var/lib/rabbitmq/.erlang.cookie
[root@node1 ~]# cat /var/lib/rabbitmq/.erlang.cookie
LBOTELUJAMXDMIXNTZMB

node1服務器中的.erlang.cookie文件,拷貝到node2服務器上:

[root@node1 ~]# scp /var/lib/rabbitmq/.erlang.cookie root@node2:/var/lib/rabbitmq

先停止運行節點,然后以后台方式啟動 RabbitMQ Server(node1node2分別執行):

[root@node1 ~]# rabbitmqctl stop
[root@node1 ~]# rabbitmq-server -detached

然后我們以node1作為集群中心,在node2上執行加入集群中心命令(節點類型為磁盤節點):

[root@node1 ~]# rabbitmqctl stop_app
[root@node1 ~]# rabbitmqctl reset 
[root@node1 ~]# rabbitmqctl join_cluster rabbit@node1
//默認是磁盤節點,如果是內存節點的話,需要加--ram參數
[root@node1 ~]# rabbitmqctl start_app

查看集群的狀態(包含node1node2節點):

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

我們可以從 RabbitMQ Web 管理界面,看到集群的信息:

5. 搭建 HAProxy 負載均衡

HAProxy 是一個免費的負載均衡軟件,可以運行於大部分主流的 Linux 操作系統上。

HAProxy 提供了 L4(TCP) 和 L7(HTTP) 兩種負載均衡能力,具備豐富的功能。HAProxy 的社區非常活躍,版本更新快速(最新穩定版 1.7.2 於 2017/01/13 推出)。最關鍵的是,HAProxy 具備媲美商用負載均衡器的性能和穩定性。它當前不僅僅是免費負載均衡軟件的首選,更幾乎成為了唯一選擇。

因為 RabbitMQ 本身不提供負載均衡,下面我們就搭建 HAProxy,用作 RabbitMQ 集群的負載均衡。

HAProxy 安裝在node1服務器上,安裝命令:

[root@node1 ~]# rpm -ivh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-5.noarch.rpm//
[root@node1 ~]# yum -y install haproxy

配置 HAProxy:

[root@node1 ~]# cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak
[root@node1 ~]# vi /etc/haproxy/haproxy.cfg

將下面的配置添加到/etc/haproxy/haproxy.cfg文件中:

global
    log     127.0.0.1  local0 info
    log     127.0.0.1  local1 notice
    daemon
    maxconn 4096

defaults
    log     global
    mode    tcp
    option  tcplog
    option  dontlognull
    retries 3
    option  abortonclose
    maxconn 4096
    timeout connect  5000ms
    timeout client  3000ms
    timeout server  3000ms
    balance roundrobin

listen private_monitoring
    bind    0.0.0.0:8100
    mode    http
    option  httplog
    stats   refresh  5s
    stats   uri  /stats
    stats   realm   Haproxy
    stats   auth  admin:admin

listen rabbitmq_admin
    bind    0.0.0.0:8102
    server  node1 node1:15672
    server  node2 node2:15672

listen rabbitmq_cluster
    bind    0.0.0.0:8101
    mode    tcp
    option  tcplog
    balance roundrobin
    timeout client  3h
    timeout server  3h
    server  node1  node1:5672  check  inter  5000  rise  2  fall  3
    server  node2  node2:5672  check  inter  5000  rise  2  fall  3

然后啟動 HAProxy:

[root@node1 ~]# haproxy -f /etc/haproxy/haproxy.cfg

外部訪問的話,需要關閉下防火牆:

[root@node1 ~]# systemctl disable firewalld.service
rm '/etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service'
rm '/etc/systemd/system/basic.target.wants/firewalld.service'
[root@node1 ~]# systemctl stop firewalld.service

HAProxy 配置了三個地址:

  • http://node1:8100/stats:HAProxy 負載均衡信息地址,賬號密碼:admin/admin
  • http://node1:8101:RabbitMQ Server Web 管理界面(基於負載均衡)。
  • http://node1:8102:RabbitMQ Server 服務地址(基於負載均衡)。

通過訪問http://node1:8100/stats,查看 HAProxy 負載均衡信息:

參考資料:


免責聲明!

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



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