本文為多宿主搭建,單機搭建可參考下方文章
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)
(零)、架構圖
(一)、創建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
??【補充】:
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,則為配置成功
??注:ha容器重啟之后kp不會自動重啟
??至此,高可用的MQ集群已經搭建完畢,對外暴露5666端口進行MQ通信,15666端口進行MQ可視化管理,ip:25666/haproxy地址進行ha管理
(五)、配置鏡像隊列(可選)
??增加一條策略即可
??Name為自定義名稱;Pattern為正則匹配,^為匹配全部;Definition為具體策略與規則,ha-mode配置高可用模式,all為全部
??隊列只能定義在一個節點上,普通模式隊列僅存在于一個節點,鏡像模式隊列存在于所有節點,+1表示額外存在的隊列數。如果是+2就表示在另外兩個節點也存在此隊列,即存在另外兩個節點
(六)、測試
??訪問haproxy的管理頁面: http://172.16.22.240:25666/haproxy
??連接rabbitmq 的5666端口并發送數據,可以在此頁面,對每次的請求轉發進行監控
??訪問rabbitmq的客戶端: http://172.16.22.240:15666
??該頁面為ha對mq集群的輪詢訪問
(七)、連接異常的問題處理
參考: 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
說了那么多,我們該怎么解決此問題呢?
兩種方案:
① 修改系統的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