Docker搭建多機多節點haproxy+keepalived負載均衡的高可用RabbitMQ集群

本文為多宿主搭建,單機搭建可參考下方文章
https://www.cnblogs.com/CaesarLinsa/p/11037613.html

??坑很多,配置要求比較嚴苛,請注意

??多物理機搭建最大的問題是,默認bridge網絡模式下docker容器使用的是bridge按照DHCP協議動態分配的子網IP,容器是虛擬網絡容器,相對于外部網絡是隔離的,所以無法通過hosts解析到外部IP,也無從連接其他mq節點

多宿主集群當前已知的搭建模式有:
① host的網絡模式(- -net host)
② 插件(Calico flannel weave Docker Overlay)
③ overlay的網絡模式
④ 內網DNS服務器提供域名解析

??這里提供host網絡模式的集群搭建,以兩臺物理機為例,網絡環境為內網

172.16.22.72 (主機)
172.16.22.59 (備機)
172.16.22.240(VIP)

(零)、架構圖

image

(一)、創建MQ容器

??兩種方法均可,均為增加hosts映射關系進行節點尋址,最終產出相同。建議采用方法一 ,后續節點擴增更靈活

  • 方法一

1.創建hosts
兩臺機器都創建/opt/rabbitmq目錄,然后在rabbitmq目錄下創建hosts文件

mkdir /opt/rabbitmq
cd /opt/rabbitmq
vi hosts
#ip            真實主機hostname(如果主機名為localhost會有一點問題,建議更改)
172.16.22.72   support
172.16.22.59   hr02

2.運行容器
當docker發現本地沒有 rabbitmq:management 的鏡像時會主動從倉庫拉取,management 為帶有管理頁面的版本

#172.16.22.72
docker run -d --net host --name rabbit1  -v /opt/rabbitmq:/var/lib/rabbitmq:z  -v /opt/rabbitmq/hosts:/etc/hosts -e RABBITMQ_ERLANG_COOKIE='RABBITMQ'  rabbitmq:management
#172.16.22.59
docker run -d --net host --name rabbit2  -v /opt/rabbitmq:/var/lib/rabbitmq:z  -v /opt/rabbitmq/hosts:/etc/hosts -e RABBITMQ_ERLANG_COOKIE='RABBITMQ'  rabbitmq:management
  • 方法二
#172.16.22.72
docker run -d --net host --name rabbit1 --add-host=support:172.16.22.72 --add-host=hr02:172.16.22.59 -e RABBITMQ_ERLANG_COOKIE='RABBITMQ'  rabbitmq:management
#172.16.22.59
docker run -d --net host --name rabbit2 --add-host=support:172.16.22.72 --add-host=hr02:172.16.22.59 -e RABBITMQ_ERLANG_COOKIE='RABBITMQ'  rabbitmq:management

??【可選】

??如果要將文件映射到宿主機方便以后遷移備份,可以添加文件映射命令如下。要注意,添加映射后不會開啟管理頁面的插件,需要進入容器手動啟用插件,原因尚未探尋

#etc存放配置,lib存放數據庫,log存放日志
-v /home/rabbitmq/etc/rabbitmq:/etc/rabbitmq -v /home/rabbitmq/lib/rabbitmq:/var/lib/rabbitmq ->v /home/rabbitmq/log/rabbitmq:/var/log/rabbitmq

??開啟插件

docker exec -it rabbit1 /bin/bash
rabbitmq-plugins enable rabbitmq_management

??【解釋】

#采用host的網絡模式
--net host
#容器命名為rabbit1
--name rabbit1  
#將宿主機的/opt/rabbitmq目錄映射到容器中的/var/lib/rabbitmq目錄,
#z是一個標記,在selinux環境下使用
-v /opt/rabbitmq:/var/lib/rabbitmq:z  
#設置env 環境變量。這里的cookie可以為任意值,所有節點保持一致即可
-e RABBITMQ_ERLANG_COOKIE='RABBITMQ'
#增加host
--add-host=support:172.16.22.72

(二)、搭建集群

??將除了第一個節點外的其他節點加入第一個節點,每個節點都執行如下命令。加入節點時,
加上--ram 命令則為創建內存節點,不加為硬盤節點

#進入容器
docker exec -it rabbit2 /bin/bash
#關閉應用
rabbitmqctl stop_app
#清除所有隊列
rabbitmqctl reset
#加入節點
rabbitmqctl join_cluster --ram rabbit@support
#啟動應用
rabbitmqctl start_app
#查看集群狀態
rabbitmqctl cluster_status
#【備用】從rabbit@support主節點上移除rabbit@hr02節點
rabbitmqctl -n rabbit@support forget_cluster_node rabbit@hr02

image

??【補充】:

tcp4369端口用于集群鄰居發現;
tcp5671,5672端口用于AMQP 0.9.1 and 1.0 clients使用;
tcp15672端口用于http api與rabbitadmin訪問,后者僅限在management plugin開啟時;
tcp25672端口用于erlang分布式節點/工具通信

??【個人理解】:
??① 節點的全稱默認為 【節點名字@主機名稱】
??② 假定節點2(hr02)要加入的節點1的全稱是【rabbit@support】,rabbitmq首先會在同一網段/橋下尋找是否存在該節點,如果不存在,會在節點2配置的hosts中尋找support對應的ip,通過4369端口進行連接。如果連接成功,節點2會告知對方,節點2想要連接的對方的節點的名稱是【rabbit@support】,對方則會按照【rabbit@support】的全名在本地進行節點搜索
??③ 如果節點1的主機名稱為localhost,那即使在節點2的hosts配置了【support - 目標ip】的映射關系,在節點1也無法搜索到【rabbit@support】這個節點,因為節點1的真實節點名稱是【rabbit@localhost】

??【節點操作】:
刪除集群中的節點:
①進入待刪除節點容器
②停止節點 rabbitmqctl stop_app
③進入主節點容器刪除待刪除節點 rabbitmqctl forget_cluster_node node_name

增加集群中的節點:
①進入待增加節點容器
②清除數據 rabbitmqctl reset
③加入集群 rabbitmqctl join_cluster 主節點名稱
④啟動節點 rabbitmqctl start_app

(三)、部署Haproxy

??第三、四步的目的是創建主備haproxy和主備對應的監測kp,重點依舊是網絡IP配置及VIP創建。
??ha安裝沒什么好說的。kp裝在宿主機、單獨容器或ha容器都可以,只不過如果要裝在ha容器或單獨容器內要用host網絡模式且容器運行的時候加- -privileged參數,否則對VIP有影響;如果kp是裝在宿主機上,ha用什么網絡模式都可以,kp只是一個全端口轉發。
??建議將kp裝在ha容器內,方便通過腳本監控ha的存活狀態。

??1.編輯haproxy配置文件如下:

mkdir /home/haproxy
vi /home/haproxy/haproxy.cfg
global
  daemon
  maxconn 10000
  #日志輸出配置,所有日志都記錄在本機,以local0的日志級別(系統不可用)輸出
  #local0~local7
  # emerg 0-系統不可用      alert 1-必須馬上采取行動的事件
  # crit 2-關鍵的事件       err 3-錯誤事件
  # warning 4-警告事件      notice 5-普通但重要的事件
  # info 6-有用的信息       debug 7-調試信息
 log 127.0.0.1 local0 info

defaults
  mode http
  #應用全局的日志配置
  log global
  #超時配置
  timeout connect 5000ms
  timeout client 5000ms
  timeout server 5000ms
  timeout check 2000ms

#負載均衡的名字(自定義)
#監聽5666端口并轉發到rabbitmq服務
listen rabbitmq_cluster
  bind 0.0.0.0:5666#對外提供的虛擬的端口
  option tcplog
  mode tcp
  #負載均衡算法為輪詢
  balance roundrobin
  #對后端服務器的健康狀況檢查間隔為2000毫秒,
  #連續2次健康檢查成功,則認為是有效的,連續3次健康檢查失敗,則認為服務器宕機
  server rabbit1 172.16.22.72:5672 check inter 5000ms rise 2 fall 3
  server rabbit2 172.16.22.59:5672 check inter 5000ms rise 2 fall 3

#haproxy的客戶頁面
listen http_front 
  bind 0.0.0.0:25666
  stats uri /haproxy #頁面地址
  #頁面的用戶名和密碼,建議主備設為不同,方便確定搶占到VIP的服務器是主機還是備機
  stats auth root:ruijie 
  stats admin if TRUE #管理界面,成功登陸后可通過webui管理節點

#rabbit管理頁面,監聽15666端口轉發到rabbitmq的客戶端
listen rabbitmq_admin 
  bind 0.0.0.0:15666
  server rabbit1 172.16.22.72:15672 check inter 5000ms rise 2 fall 3
  server rabbit2 172.16.22.59:15672 check inter 5000ms rise 2 fall 3

??2.創建haproxy容器
??這里采用host模式進行創建,使用宿主機的網卡,否則KP創建的VIP是容器內VIP而不是容器外VIP

#-v 中的參數:ro表示read only,宿主文件為只讀。如果不加此參數默認為rw,即允許容器對宿主文件的讀寫
#一定要添加--privileged參數,使用該參數,container內的root擁有真正的root權限。
#否則,container內的root只是外部的一個普通用戶權限(無法創建網卡)
docker run -d --name cluster-rabbit-haproxy --privileged --net host -v /home/haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro haproxy

??3.在備機上以同樣的配置和命令創建一臺備份haproxy

(四)、安裝keepalived

??這里采用的方式是將kp安裝在haproxy容器內

1.進入haproxy容器

docker exec -it cluster-rabbit-haproxy /bin/bash

2.更新,安裝keepalived

apt-get update
apt-get install keepalived

3.安裝ifconfig,安裝ping,安裝vim,安裝ps

apt-get install net-tools
apt-get install iputils-ping
apt-get install vim
apt-get install procps

4.創建kp配置文件

vi /etc/keepalived/keepalived.conf
#keepalived配置文件
global_defs {
    router_id NodeA                 #路由ID, 主備的ID不能相同
    notification_email {
        xxx@xxx.com
    }
    notification_email_from xxx@xxx.com
    smtp_server 127.0.0.1
    smtp_connect_timeout 30
    vrrp_skip_check_adv_addr
    #在keepalived的服務器上配合使用nginx或haproxy時,需要把這一項注掉,否則VIP ping不通,80端口也無法正常訪問
    # vrrp_strict 
    vrrp_garp_interval 0
    vrrp_gna_interval 0
}

#自定義監控腳本
vrrp_script chk_haproxy {
        script "/etc/keepalived/check_haproxy.sh"
        interval 5
        weight 2
}

vrrp_instance VI_1 {
        state MASTER #Master為主機,備機設為BACKUP
        interface ens160        #指定網卡(宿主機真實網卡,ip a查看)
        virtual_router_id 1
        priority 100            #優先級,BACKUP機器上的優先級要小于這個值
        advert_int 1            #設置主備之間的檢查時間,單位為s
        authentication {        #定義驗證類型和密碼,主備需相同
                auth_type PASS
                auth_pass ruijie
        }
        track_script {
                chk_haproxy     #ha存活監控腳本
        }
        virtual_ipaddress {     #VIP地址,可為多個。如果有需要可以部署雙機雙VIP
           172.16.22.240
        }
}

??【補充】關于雙機雙VIP(參考@dloux_zc)
??A B 雙機, 正常情況下A綁定vip1, B綁定vip2;頂層通過dns解析將不同的域名分別指向其中一個vip, 以充分利用服務器資源;
??在發生故障時,A或B上同時綁定兩個VIP。
??在大流量的情況下不建議這么用,如果AB 都接近滿載,一旦發生故障,其中一臺的流量全部導到另一臺,可能很快將另一臺服務器也壓崩。
??僅作測試及小流量情況又不想浪費備機資源的情況下使用。

??5.配置監控腳本

vi /etc/keepalived/check_haproxy.sh
#!/bin/bash
if [ $(ps -C haproxy --no-header | wc -l) -eq 0 ];then
        haproxy -f /usr/local/etc/haproxy/haproxy.cfg
fi
sleep 2
if [ $(ps -C haproxy --no-header | wc -l) -eq 0 ];then
        #service keepalived stop
        /etc/init.d/keepalived stop
fi

??6.啟動

service keepalived start

??7.查看配置是否成功

ip a

??使用的網卡出現虛擬ip,則為配置成功


image

??注:ha容器重啟之后kp不會自動重啟

??至此,高可用的MQ集群已經搭建完畢,對外暴露5666端口進行MQ通信,15666端口進行MQ可視化管理,ip:25666/haproxy地址進行ha管理

(五)、配置鏡像隊列(可選)

??增加一條策略即可

image

??Name為自定義名稱;Pattern為正則匹配,^為匹配全部;Definition為具體策略與規則,ha-mode配置高可用模式,all為全部
image

??隊列只能定義在一個節點上,普通模式隊列僅存在于一個節點,鏡像模式隊列存在于所有節點,+1表示額外存在的隊列數。如果是+2就表示在另外兩個節點也存在此隊列,即存在另外兩個節點
image

(六)、測試

??訪問haproxy的管理頁面: http://172.16.22.240:25666/haproxy
??連接rabbitmq 的5666端口并發送數據,可以在此頁面,對每次的請求轉發進行監控

image

??訪問rabbitmq的客戶端: http://172.16.22.240:15666
??該頁面為ha對mq集群的輪詢訪問
image

(七)、連接異常的問題處理

參考: https://www.cnblogs.com/xishuai/p/rabbitmq-and-haproxy-channel-shutdown-connection-error.html

??SpringBoot連接集群可能會有 Channel shutdown: connection error 連接錯誤的問題,
報錯信息如下:

2019-11-18 16:55:23 INFO o.s.a.r.l.SimpleMessageListenerContainer: Restarting Consumer@7925e772: tags=[[amq.ctag-NKT1PBwEVFNlR6zlAklF4A, amq.ctag-QHdxvp2TeHV-7d26AonMPA]], channel=Cached Rabbit Channel: AMQChannel(amqp://guest@172.16.22.240:5666/AS_System_Event,2), conn: Proxy@fe156f4 Shared Rabbit Connection: SimpleConnection@bb21063 [delegate=amqp://guest@172.16.22.240:5666/AS_System_Event, localPort= 61176], acknowledgeMode=MANUAL local queue size=0
2019-11-18 16:55:23 INFO       o.s.a.r.c.CachingConnectionFactory: Attempting to connect to: [172.16.22.240:5666]
2019-11-18 16:55:23 INFO       o.s.a.r.c.CachingConnectionFactory: Created new connection: connectionFactory#68c4a860:1/SimpleConnection@f36276b [delegate=amqp://guest@172.16.22.240:5666/AS_System_Event, localPort= 61190]
2019-11-18 16:55:27 ERROR      o.s.a.r.c.CachingConnectionFactory: Channel shutdown: connection error

??從紅框可以看得出來,springboot一直在重復【重啟消費者——連接服務端——創建新連接——連接異常】,而綠框則為輪詢請求的兩個服務端。參考鏈接文章確定問題為客戶端連接超時:

??為什么會出現此問題呢?因為 HAProxy 配置了客戶端連接超時參數 timeout client ms,如果客戶端連接超過配置的此參數,那么 HAProxy 將會刪除這個客戶端連接。
??RabbitMQ 客戶端使用永久連接到代理,從不超時,那為什么還會出現問題?因為如果 RabbitMQ 在一段時間內處于非活動狀態,那么 HAProxy 將自動關閉連接

image

引用原文:

image

說了那么多,我們該怎么解決此問題呢?
兩種方案:
① 修改系統的tcp_keepalive_time配置,間隔時間低于 HAProxy 配置的timeout client超時時間(因為有可能影響其他系統服務,不推薦)。
② 修改 HAProxy 中的timeout client超時時間,配置大于系統的tcp_keepalive_time間隔時間(推薦)。因為系統tcp_keepalive_time發送TCP keepalive數據包間隔時間是 2 個小時,所以,我們將 HAProxy 中的timeout client超時時間,設置為 3 個小時

配置文件完整示例:

global
  daemon
  ...

defaults
  ...

listen rabbitmq_cluster
   bind 0.0.0.0:5666
  option tcplog
  timeout client  3h
  timeout server  3h
  mode tcp
  balance roundrobin
  server rabbit1 172.16.22.72:5672 check inter 5000ms rise 2 fall 3
  server rabbit2 172.16.22.59:5672 check inter 5000ms rise 2 fall 3

listen http_front 
  ...

listen rabbitmq_admin 
  ...

??重新運行 HAProxy,系統正常運行無異常

參考:
https://blog.csdn.net/qq_21108311/article/details/82973763#commentBox
https://www.cnblogs.com/CaesarLinsa/p/11037613.html
https://blog.csdn.net/kevin3101/article/details/86579311

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,250評論 6 530
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 97,923評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,041評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,475評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,253評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,801評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,882評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,023評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,530評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,494評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,639評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,177評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,890評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,289評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,552評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,242評論 3 389
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,626評論 2 370