docker rabbitmq

docker run -d --hostname my1 --name dome-rabbit -p 15673:5672 -p 15674:15672 -e RABBITMQ_ERLANG_COOKIE='YZSDHWMFSMKEMBDHSGGZ' --dns $(docker inspect -f '{{.NetworkSettings.IPAddress}}' dns) --dns-search rabbit.com dockerhub.chinaso365.com:5043/rabbitmq:3.6.1-managementhtml


docker run -d -h my --name some-rabbit -p 5672:5672 -p 15672:15672 -e RABBITMQ_ERLANG_COOKIE='YZSDHWMFSMKEMBDHSGGZ' --dns $(docker inspect -f '{{.NetworkSettings.IPAddress}}' dns) --dns-search rabbit.com dockerhub.chinaso365.com:5043/rabbitmq:3.6.1-management前端


cat << EOF > /etc/hosts
172.17.0.13 my
172.17.0.14 my1
# test data
EOFnode

 

Rabbitmq集羣高可用git

RabbitMQ是用erlang開發的,集羣很是方便,由於erlang天生就是一門分佈式語言,但其自己並不支持負載均衡。github

Rabbit模式大概分爲如下三種:單一模式、普通模式、鏡像模式正則表達式

單一模式:最簡單的狀況,非集羣模式。redis

沒什麼好說的。docker

普通模式:默認的集羣模式。安全

對於Queue來講,消息實體只存在於其中一個節點,A、B兩個節點僅有相同的元數據,即隊列結構。bash

當消息進入A節點的Queue中後,consumer從B節點拉取時,RabbitMQ會臨時在A、B間進行消息傳輸,把A中的消息實體取出並通過B發送給consumer。

因此consumer應儘可能鏈接每個節點,從中取消息。即對於同一個邏輯隊列,要在多個節點創建物理Queue。不然不管consumer連A或B,出口總在A,會產生瓶頸。

該模式存在一個問題就是當A節點故障後,B節點沒法取到A節點中還未消費的消息實體。

若是作了消息持久化,那麼得等A節點恢復,而後纔可被消費;若是沒有持久化的話,而後就沒有而後了……

鏡像模式:把須要的隊列作成鏡像隊列,存在於多個節點,屬於RabbitMQ的HA方案

該模式解決了上述問題,其實質和普通模式不一樣之處在於,消息實體會主動在鏡像節點間同步,而不是在consumer取數據時臨時拉取。

該模式帶來的反作用也很明顯,除了下降系統性能外,若是鏡像隊列數量過多,加之大量的消息進入,集羣內部的網絡帶寬將會被這種同步通信大大消耗掉。

因此在對可靠性要求較高的場合中適用(後面會詳細介紹這種模式,目前咱們搭建的環境屬於該模式)

 

瞭解集羣中的基本概念:

RabbitMQ的集羣節點包括內存節點、磁盤節點。顧名思義內存節點就是將全部數據放在內存,磁盤節點將數據放在磁盤。不過,如前文所述,若是在投遞消息時,打開了消息的持久化,那麼即便是內存節點,數據仍是安全的放在磁盤。

一個rabbitmq集 羣中能夠共享 user,vhost,queue,exchange等,全部的數據和狀態都是必須在全部節點上覆制的,一個例外是,那些當前只屬於建立它的節點的消息隊列,儘管它們可見且可被全部節點讀取。rabbitmq節點能夠動態的加入到集羣中,一個節點它能夠加入到集羣中,也能夠從集羣環集羣會進行一個基本的負載均衡。
集羣中有兩種節點:
1 內存節點:只保存狀態到內存(一個例外的狀況是:持久的queue的持久內容將被保存到disk)
2 磁盤節點:保存狀態到內存和磁盤。
內存節點雖然不寫入磁盤,可是它執行比磁盤節點要好。集羣中,只須要一個磁盤節點來保存狀態 就足夠了
若是集羣中只有內存節點,那麼不能中止它們,不然全部的狀態,消息等都會丟失。

 思路:

那麼具體如何實現RabbitMQ高可用,咱們先搭建一個普通集羣模式,在這個模式基礎上再配置鏡像模式實現高可用,Rabbit集羣前增長一個反向代理,生產者、消費者經過反向代理訪問RabbitMQ集羣。

架構圖以下:圖片來自http://www.nsbeta.info

 
          上述圖裏是3個RabbitMQ運行在同一主機上,分別用不一樣的服務端口。固然咱們的生產實際裏,多個RabbitMQ確定是運行在不一樣的物理服務器上,不然就失去了高可用的意義。

 

 

  • 集羣模式配置

設計架構能夠以下:在一個集羣裏,有4臺機器,其中1臺使用磁盤模式,另2臺使用內存模式。2臺內存模式的節點,無疑速度更快,所以客戶端(consumer、producer)鏈接訪問它們。而磁盤模式的節點,因爲磁盤IO相對較慢,所以僅做數據備份使用,另一臺做爲反向代理。

 這種模式更適合非持久化隊列,只有該隊列是非持久的,客戶端才能從新鏈接到集羣裏的其餘節點,並從新建立隊列。假如該隊列是持久化的,那麼惟一辦法是將故障節點恢復起來。  

      爲何RabbitMQ不將隊列複製到集羣裏每一個節點呢?這與它的集羣的設計本意相沖突,集羣的設計目的就是增長更多節點時,能線性的增長性能(CPU、內存)和容量(內存、磁盤)。理由以下:

1. storage space: If every cluster node had a full copy of every queue, adding nodes wouldn’t give you more storage capacity. For example, if one node could store 1GB of messages, adding two more nodes would simply give you two more copies of the same 1GB of messages.

2. performance: Publishing messages would require replicating those messages to every cluster node. For durable messages that would require triggering disk activity on all nodes for every message. Your network and disk load would increase every time you added a node, keeping the performance of the cluster the same (or possibly worse).

固然RabbitMQ新版本集羣也支持隊列複製(有個選項能夠配置)。好比在有五個節點的集羣裏,能夠指定某個隊列的內容在2個節點上進行存儲,從而在性能與高可用性之間取得一個平衡。

     
  • 鏡像模式配置
上面配置RabbitMQ默認集羣模式,但並不保證隊列的高可用性,儘管交換機、綁定這些能夠複製到集羣裏的任何一個節點,可是隊列內容不會複製,雖然該模式解決一部分節點壓力,但隊列節點宕機直接致使該隊列沒法使用,只能等待重啓,因此要想在隊列節點宕機或故障也能正常使用,就要複製隊列內容到集羣裏的每一個節點,須要建立鏡像隊列。
咱們看看如何鏡像模式來解決複製的問題,從而提升可用性 
 
         
 
      step1:增長負載均衡器
 

關於負載均衡器,商業的好比F5的BIG-IP,Radware的AppDirector,是硬件架構的產品,能夠實現很高的處理能力。但這些產品昂貴的價格會讓人止步,因此咱們還有軟件負載均衡方案。互聯網公司經常使用的軟件LB通常有LVS、HAProxy、Nginx等。LVS是一個內核層的產品,主要在第四層負責數據包轉發,使用較複雜。HAProxy和Nginx是應用層的產品,但Nginx主要用於處理HTTP,因此這裏選擇HAProxy做爲RabbitMQ前端的LB。

HAProxy的安裝使用很是簡單,在Centos下直接yum install haproxy,而後更改/etc/haproxy/haproxy.cfg 文件便可,文件內容大概以下:

   #---------------------------------------------------------------------
    defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000
 
    listen rabbitmq_cluster 0.0.0.0:5672
    mode tcp
    balance roundrobin
    server   rqslave1 172.16.3.107:5672 check inter 2000 rise 2 fall 3   
    server   rqslave2 172.16.3.108:5672 check inter 2000 rise 2 fall 3 
#  server   rqmaster 172.16.3.32:5672 check inter 2000 rise 2 fall 3  
#---------------------------------------------------------------------
 
負載均衡器會監聽5672端口,輪詢咱們的兩個內存節點172.16.3.10七、172.16.3.108的5672端口,172.16.3.32爲磁盤節點,只作備份不提供給生產者、消費者使用,固然若是咱們服務器資源充足狀況也能夠配置多個磁盤節點
,這樣磁盤節點除了故障也不會影響,除非同時出故障。
 
step2:配置策略
 
使用Rabbit鏡像功能,須要基於rabbitmq策略來實現,政策是用來控制和修改羣集範圍的某個vhost隊列行爲和Exchange行爲
 
在cluster中任意節點啓用策略,策略會自動同步到集羣節點
 
rabbitmqctl set_policy -p hrsystem ha-allqueue"^" '{"ha-mode":"all"}'#
 
這行命令在vhost名稱爲hrsystem建立了一個策略,策略名稱爲ha-allqueue,策略模式爲 all 即複製到全部節點,包含新增節點,
策略正則表達式爲 「^」 表示全部匹配全部隊列名稱。
例如rabbitmqctl set_policy -p hrsystem ha-allqueue "^message" '{"ha-mode":"all"}'
注意:" ^message " 這個規則要根據本身修改,這個是指同步"message"開頭的隊列名稱,咱們配置時使用的應用於全部隊列,因此表達式爲"^"
官方set_policy說明參見
set_policy [-p  vhostpath] { name} { pattern} { definition} [ priority]
 
ha-mode:
 
ha-mode ha-params Result
all (absent) Queue is mirrored across all nodes in the cluster. When a new node is added to the cluster, the queue will be mirrored to that node.
exactly count Queue is mirrored to count nodes in the cluster. If there are less than count nodes in the cluster, the queue is mirrored to all nodes. If there are more than countnodes in the cluster, and a node containing a mirror goes down, then a new mirror will not be created on another node. (This is to prevent queues migrating across a cluster as it is brought down.)
nodes node names Queue is mirrored to the nodes listed in node names. If any of those node names are not a part of the cluster, this does not constitute an error. If none of the nodes in the list are online at the time when the queue is declared then the queue will be created on the node that the declaring client is connected to.
 
step3:
建立隊列時須要指定ha 參數,若是不指定x-ha-prolicy 的話將沒法複製
 
下面C#代碼片斷
 using ( var bus = RabbitHutch.CreateBus(ConfigurationManager .ConnectionStrings["RabbitMQ"].ToString()))
            {
                bus.Subscribe< TestMessage>("word_subscriber" , message => RunTable(message),x=>x.WithArgument("x-ha-policy" , "all"));
                Console.WriteLine("Subscription Started. Hit any key quit" );
                Console.ReadKey();
            }
 
step4:
客戶端使用負載服務器172.16.3.110 (panyuntao3)發送消息,隊列會被複制到全部節點,固然策略也能夠配置制定某幾個節點,這時任何節點故障 、或者重啓將不會影響咱們正常使用某個隊列
 到這裏咱們完成了高可用配置(全部節點都宕機那沒有辦法了)。
 
使用rabbitmq管理端能夠看到集羣鏡像模式中對列狀態

集羣部署

使用Docker官方RabbitMQ鏡像部署不能成功

直接從官方鏡像建立後,加入集羣提示的錯誤(Error: unable to connect to nodes [rabbitmq1@rabbitmq1]...),節點沒法直接與另外一節點直接通信,增長--link也失敗。假如增長--link可行,那必須將全部集羣中的節點都使用--link進行連接,這樣就存在一個問題,後來新增的節點怎麼辦? 

後來想到直接修改hosts文件,不過這種方式也比較麻煩,須要逐個修改。 

最後本人在網絡中找到一個使用DNS的方式,這種方式應該更加合理。本人也作了一些簡單修改,從最新鏡像建立容器。

使用方法:git clone項目後,只需運行其中的launch.sh腳本,便可一鍵建立集羣,默認3個節點。也可閱讀後面的步驟,逐步手工建立。

 原做者jrlangford的 Shell腳本

本人修改後的 Shell腳本

步驟1. 建立DNS

docker run --name dns \
-v /var/run/docker.sock:/docker.sock \
--restart='always' \
-d \
phensley/docker-dns --domain rabbit.com

 

步驟2. 建立節點

docker run -d \
--name=rabbitmq1 \
-p 5672:5672 \
-p 15672:15672 \
-e RABBITMQ_NODENAME=rabbitmq1 \
-e RABBITMQ_ERLANG_COOKIE='YZSDHWMFSMKEMBDHSGGZ' \
-h rabbitmq1.rabbit.com \
--dns $(docker inspect -f '{{.NetworkSettings.IPAddress}}' dns) \
--dns-search rabbit.com \
rabbitmq:3.5-management

 

步驟3. 加入集羣

#磁盤節點
docker exec rabbitmq2 bash -c \
"rabbitmqctl stop_app && \
rabbitmqctl reset && \
rabbitmqctl join_cluster rabbitmq1@rabbitmq1 && \
rabbitmqctl start_app"
內存節點 
docker exec rabbitmq3 bash -c \
"rabbitmqctl stop_app && \
rabbitmqctl reset && \
rabbitmqctl join_cluster --ram rabbitmq1@rabbitmq1 && \
rabbitmqctl start_app"

 

步驟4. 設置鏡像隊列

設置全部隊列爲鏡像隊列,除了amq開頭的交換器綁定隊列。 生成環境不建議這種處理, 應該設置部分隊列爲鏡像隊列。

docker exec rabbitmq1 rabbitmqctl set_policy HA '^(?!amq\.).*' '{"ha-mode": "all"}'

 

步驟5. 退出集羣

docker exec rabbitmq3 bash -c \
"rabbitmqctl stop_app && \
rabbitmqctl reset && \
rabbitmqctl start_app"

 

集羣重啓

集羣節點的關閉順序與節點的啓動順序相反,即最後關閉的最早啓動,而且最後關閉的節點必須是磁盤節點。請務必遵照按此步驟處理,不然可能形成集羣沒法啓動,形成元數據,消息丟失的狀況。
Docker容器不一樣於虛擬機或主機,容器內部署的應用沒法啓動,基本上這個容器就廢了。Docker如今不容許作一些已建立容器的啓動參數調整。

集羣部署、運行準則

1. 保證集羣中至少有一個在線,那怕這個節點是內存節點.2. 若是關閉整個集羣節點,必須按照順序逐個關閉,而且最後一個關閉節點務必爲磁盤節點。在啓動時倒着順序啓動。(如關閉順序r1,r2,r3.那麼啓動順序爲r3,r2,r1).3. 集羣中若是使用了虛擬技術(Docker,VM),虛擬節點不能全在同一臺物理機中。(你不能保證物理機不會宕機,若是宕機基本上集羣是啓動不了的.你不知道關閉順序,你就沒法肯定啓動順序,而且宕機關閉時間可能RabbitMQ節點都沒有反應過來,沒法作一些集羣狀態處理。) 

相關文章
相關標籤/搜索