關於RabbitMq你必須深刻理解的內容

關於RabbitMq你必須深刻理解的內容

前言

這裏主要想整理關於消息隊列rabbitmq可能遇到問題,躺一躺其中的坑,而後在團隊沉澱下來,最終變爲整個團隊的技術能力,而後寫着寫着發現,官方文檔寫的都比較詳細也比較好,因此抽取一些比較有價值的連接和和整理一些實際上遇到的問題和處理心得,因此這裏分享出來,設計到的連接可能會相對較多。html

這裏假設用戶已經對rabbitmq有所瞭解,若是不瞭解,能夠先按照這個方式來測試消息隊列,如何使用該消息隊列(官方也有完整的示例)。前端

rabbitmq是一種普遍應用於互聯網的消息隊列,是一種異步的消息隊列,支持多種消息協議,支持多種開發語言,支持多種隊列集羣化方式clusterfederation,還有完善的受權機制,集羣管理和支持各類插件node

一些資料

  • 書籍
    rabbitmq實戰這本書能夠做爲一種學習消息隊列,學習rabbitmq的一種入門書籍,書中介紹了大多數rabbitmq消息隊列的相關內容,不過感受沒有官方文檔的資料好,和詳細(官方文檔是真的寫的很詳細)
  • 代碼解析(淘寶團隊在使用的時候作了一些測試和研究)
    淘寶代碼中文譯版 詳細的中文翻譯文檔,對於不熟悉erlang語言會有所幫助
    淘寶關於rabbitmq的相關實驗 裏邊有不少經驗和分析

認爲比較值得看的內容:mysql

我認爲比較重要的幾個內容linux

  • 集羣配置 裏邊詳細了配置相關的細節
  • 客戶端工具 各類管理工具
  • 訪問控制 涉及了各個模塊認證和受權管理等
  • 網絡 介紹了端口,加密,調整tcp參數,內核參數,proxy化等
  • 集羣管理監控 rabbitmq提供了很是完善的client和web工具,能很容易的接入集羣管理,查看集羣信息,甚至進行集羣狀態維護
  • 集羣 詳細介紹了集羣搭建,故障,恢復,全部可能遇到的問題
  • 鏡像隊列 同步鏡像,分佈式系統副本的實現,頗有必要了解具體的實現細節,好比對比和mysql master-slave的差異?
  • 可靠性 這裏介紹了rabbitmq如何解決各類故障問題的場景,包括生產者,消費者,集羣模式等
  • 生產環境chekclist 下邊會有介紹
  • 內存使用 消息隊列內存使用和內部信息
  • 集羣鏡像同步 這一節內容很重要,設計到分佈式系統的集羣同步與可用,也有failover

整理

列舉幾個對集羣管理相對重要的:git

  • rabbitmq-production-check list
    連接: checklist
    常規來說有幾個重要chekc-list
    • virtual Host / user Name / password 須要單獨給不一樣服務給不一樣的vhost, 帳戶密碼,有一種按照服務進行一種資源隔離的思想,而後獨立受權,這其實對mq來說是一種優點,會增長集羣吞吐量,具體詳情能夠看上邊關於生產速率的問題。
    • 設置能讓mq良好運行的限制參數 vm_memory_high_watermark / disk_free_limit
    • 設置種種參數, 處理大量鏈接 large-number-of-connetions,包括了socket文件描述符限制,tcp內核參數調優(這裏很是有價值),集羣資源控制,cpu, mem, channel等(這對於設計服務端程序也頗有幫助)
    • 防火牆策略,設置訪問策略,開啓對集羣內部,集羣外部須要設置開放的端口訪問,關閉非開放端口和ip的訪問權限
    • 集羣分區策略 partitions,這裏離很是重要,下邊會有一段介紹。


  • 集羣核心配置文件
    連接: configure
    總體常規來說相對重要的參數:
    • listeners.tcp.default defualt=5672 監聽地址
    • num_acceptors.tcp default=10 接受tcp監聽erlang進程數量(這塊就和linux io相關的感受會比較多)
    • vm_memory_high_watermark.relative default=0.4 內存到達必定容量觸發流控程序 mem-flow-control
    • disk_free_limit default=50M 磁盤free到達必定數量觸發流控dis-flow-control|
    • channel_max default=2047 鏈接客戶端數量
    • cluster_partition_handling default=ignore 分區配置策略,集羣化很是重要的參數!! partitions|

一些環境變量配置:
github

  • RABBITMQ_IO_THREAD_POOL_SIZE default=128(linux) mq io線程數量pool-thread|
  • RABBITMQ_MNESIA_BASE RABBITMQ_MNESIA_BASE/{NODE} 數據持久化目錄

rabbitmq集羣可能遇到的問題

場景1 : 在分佈式隊列中的非鏡像隊列

  • 更新cluster方式集羣結構可能致使部分非鏡像隊列內容丟失(非使用這種Federated這種藍綠髮布方式),集羣更新方式是按照clustering集羣的進行的。

注意: 這裏提到的負載均衡器是4層的負載均衡,使用輪訓的方式將請求轉發給後端,能夠假設爲haproxy, lvsweb

環境: 

        node:  rabbitmq-01, rabbitmq-02, rabbitmq-03 
        queue: 存在節點爲非鏡像隊列
        前端負載均衡器: TCP --> rabbitmq-01/rabbitmq-02/rabbitmq-03

    需求: 

        2個節點須要下架,更換新的節點

        rabbitmq-02 ---> rabbitmq-02-new
        rabbitmq-03 ---> rabbitmq-03-new

    操做:  

        業務低峯期將rabbitmq-02-new,rabbitmq-03-new join到集羣節點,而後刪除rabbitmq-01, rabbitmq-02
複製代碼
  • 存在問題:
    因爲更新節點結構,會致使非鏡像隊列內容丟失,可能部分服務異常。緣由是rabbitmq集羣模式會在集羣的元數據會保存到全部節點上(meta數據),可是非鏡像隊列的消息內容(持久化或則內存)只會保存到單個節點,客戶端鏈接負載均衡器,而後路由隨機轉發到後端節點,後端節點再轉發到數據節點,而後因爲 rabbitmq-02, rabbitmq-03 節點已經下架,因此數據就會丟失的狀況。
  • 注意點: 對於核心隊列須要配置鏡像模式(須要考慮節點位置和路由信息,涉及到數據同步的問題,同步會帶來性能消耗和資源消耗),當業務部門須要使用消息隊列,須要明確消息隊列的可靠性,具體使用服務資源,和數據量等相關資源。
  • 建立鏡像隊列多種方式方式
    • management UI (UI-->Admin-->Policies)
    • rabbitmqctl
    • 代碼中指定argument建立(rabbitmq3.0後不支持了)

開發人員推薦使用代碼中建立(rabbitmq3.0後不支持...3.0後都是create ha) | 這裏略坑-- --sql

queue_args={"x-ha-policy" : "all"}
    channel.queue_declare{queue="hello-queue", arguments=queue_args}
複製代碼

場景2 : 在分佈式隊列中的腦裂處理

腦裂: 腦裂問題是分佈式系統中最多見的問題,指在一個高可用(HA)系統中,當聯繫着的兩個節點斷開聯繫時,原本爲一個總體的系統,分裂爲兩個獨立節點,這時兩個節點開始爭搶共享資源,結果會致使系統混亂,數據損壞。對於無狀態服務的HA,無所謂腦裂不腦裂;但對有狀態服務,數據相關服務(好比MySQL,消息隊列)的HA,必需要嚴格防止腦裂。(但有些生產環境下的系統按照無狀態服務HA的那一套去配置有狀態服務,結果可想而知...),有一些存儲系統像數據庫,kv存儲都已經有很好的一致性協議解決了raft paxos協議解決了,這裏咱們須要格外注意這裏的腦裂處理流程。docker

腦裂帶來的最大問題就是分區問題,分區在rabbitmq中有三種配置模式ignore(默認方式), pause_minority, autoheal

  • ignore: 假設你的集羣運行在網絡很是可靠的狀況,全部的節點都是在相同交換機下,而後交換機在將流量路由到外部。若是任何其餘羣集發生故障(或者有一個雙節點羣集,不但願運行任何羣集關閉的任何風險。
  • pause_minority: 假設你的網絡不太可靠,你的節點跨域了通地域多個數據中心,而後數據中心可能會異常,你但願到集羣某個中心異常的時候,其餘兩個數據中心服務繼續工做,當數據中心恢復後,節點能自動增長到集羣中。就像阿里雲的可用區同樣。
  • autoheal: 假設你的網絡可能不可靠,你更關注服務的連續性而不是數據完整性,這個時候可能有一個雙節點羣集。

這裏只測試ignore, pause_minority

  • 環境
    rabbitmq集羣默認是3節點: rabbitmq-01(A), rabbitmq-02(B), rabbitmq-03(C)
環境: 

        node:  rabbitmq-01, rabbitmq-02, rabbitmq-03 
        queue: 鏡像隊列
        前端負載均衡器: TCP --> rabbitmq-01/rabbitmq-02/rabbitmq-03
複製代碼

2.1 網絡分區策略爲: 默認模式 ignore

設置C-->B不能互通
複製代碼
  • 操做單個節點,設置該節點到其餘節點網絡異常

iptables -I INPUT -s {NODEX} -j REJECT 這裏是表明涉及節點關閉某個ip數據包的流入

而後查看一下集羣運行狀態,顯示已經存在分區partitions

[{nodes,
       [{disc,
           ['rabbit@rabbitmq-test001','rabbit@rabbitmq-test002',
            'rabbit@rabbitmq-test003']}]},
    {running_nodes,['rabbit@rabbitmq-test003']},
    {cluster_name,<<"rabbit@rabbitmq-test001">>},
    {partitions,
      [{'rabbit@rabbitmq-test003',
           ['rabbit@rabbitmq-test001','rabbit@rabbitmq-test002']}]},
    {alarms,[{'rabbit@rabbitmq-test003',[]}]}]
複製代碼

對應與web上看,相互檢測失敗,相互顯示爲not running

node2
node1


雖然ABC C-->A -->B能夠通,都能邏輯互通,局部不互通仍是會出現 分區


圖中能夠看到已經檢測到節點down了

注意點: 這時候很是重要的一點是負載均衡器存在一個較大的隱患,就是ABC互通存在問題,不過負載均衡器可以正常鏈接到ABC,那麼請求仍是會按照正常的邏輯走,這裏就容易產生數據不一致。(因爲rabbitmq沒有實現相似raft的分佈式協議,因此這一點很重要),這就是rabbitmq集羣默認分區方式ignore最大的問題,它不會自動處理,也不會有集羣選舉的功能,須要咱們自身手動去處理集羣,去選擇信任的分區模式,這裏必定要格外注意,稍有差池就會致使集羣狀態數據異常。

  • 節點恢復
    後邊儘管節點恢復通訊,可是因爲已經出現了分區,因此仍是須要手工處理。
  • 重啓處理方式:

選擇一個你信任的分區,而後重啓全部其餘分區的節點,而後從新加入節點,注意其餘分區節點的數據會被丟掉.

web界面也會有異常顯示

而後重啓全部節點恢復警告

  • 問題:

默認模式下,會致使腦裂,丟數據,還須要手工處理,對系統可靠性要求較高的場景必定不能使用,同時運維起來會比較麻煩,成本較高,這是系統默認的配置方式,請必定根據自身場景進行配置。

2.2 網絡分區策略爲: 模式 pause_minority (這也是咱們推薦使用的方式)

設置C-->B不能互通
複製代碼

這裏不會出現分區,pause_minority

集羣切換日誌

分析:

  • 按照這種模式下,集羣會選擇大多數>1/2節點的區域爲分區優勝區域。失敗區域會被自動關閉異常端口,異常端口包括15672(web端口), 5672(amqp協議端口), 25672(通訊端口)
  • erlang發現端口 4369 接口繼續工做,不會被down掉,而後當檢測到集羣網絡恢復集羣會將異常節點自動加入集羣,而後異常節點會自動啓動web, amqp, cluster相關端口
  • 這個時候須要注意一點,若是對master的數據可靠性較高,須要手工同步,rabbitmq的同步模式sync決定的,模式的模式爲ha-sync-mode: manual(詳情仍是參看sync),,默認不會同步歷史中的推擠消息,只會同步新的消息,注意這一點也致使,可能當master異常會致使丟失部分數據

贊: 這時候會有網絡分區模式會自動關閉異常節點,負載均衡器也會報警,這樣安全級別會較高,當節點<1/2 節點也會正常服務,當從新加入集羣而後數據也能正常恢復。

總結:

rabbitmq已經一個使用普遍的消息隊列,設計模式相對完善,也在移動互聯網中已經被大量應用,可能正式因爲這樣緣由,rabbitmq有太多可配置的功能選項和隱藏配置了,因此考慮了各類各樣的適用應用場景,因此若是咱們在生產環境使用,須要對它進行一個全方面的學習和掌握,針對自身的環境進行集羣配置和集羣調優。

其餘

列舉幾條本身用的相對自動的搭建流程吧,搭建3集羣rabbitm-server

centos7-64關於一鍵安裝server:

## 安裝docker 相關的,主要是爲了增長監控使用
sudo yum update -y 
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce -y
systemctl start docker

## 安裝erlang環境與rabbitmq-server部署

sudo yum install deltarpm -y
wget --content-disposition https://packagecloud.io/rabbitmq/erlang/packages/el/7/erlang-20.0.5-1.el7.centos.x86_64.rpm/download.rpm
sudo yum install -y erlang-20.0.5-1.el7.centos.x86_64.rpm
sudo yum install -y socat
#wget https://dl.bintray.com/rabbitmq/all/rabbitmq-server/3.7.5/rabbitmq-server-3.7.5-1.el7.noarch.rpm
wget download.hyahm.com/rabbitmq-server-3.7.5-1.el7.noarch.rpm
yum install rabbitmq-server-3.7.5-1.el7.noarch.rpm -y
chkconfig rabbitmq-server on
mkdir -p /var/data/rabbitmq && chown rabbitmq:rabbitmq /var/data/rabbitmq && chmod 755 /var/data/rabbitmq
echo 'RABBITMQ_MNESIA_BASE=/var/data/rabbitmq' >> /etc/rabbitmq/rabbitmq-env.conf
echo 'ulimit -S -n 4096' >> /etc/rabbitmq/rabbitmq-env.conf
echo 'cluster_partition_handling=pause_minority' >> /etc/rabbitmq/rabbitmq.conf

## 打開防火牆
iptables -I INPUT -p tcp -s xxxx --dport 25672  -j ACCEPT
iptables -I INPUT -p tcp -s xxx--dport 4369  -j ACCEPT
iptables -I INPUT -p tcp --dport 5672 -j ACCEPT

### 選擇須要訪問的內網地址
iptables -I INPUT -s 192.168.0.0/16 -j ACCEPT
iptables -I INPUT -s 172.17.0.0/16 -j ACCEPT
複製代碼

集羣化:

  • 使用同步工具或手工不一樣文件 /var/lib/rabbitmq/.erlang.cookie
# on rabbit1
rabbitmq-server -detached
# on rabbit2
rabbitmq-server -detached
# on rabbit3
rabbitmq-server -detached
複製代碼
  • cluster
# on rabbit1
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit1 ...
# => [{nodes,[{disc,[rabbit@rabbit1]}]},{running_nodes,[rabbit@rabbit1]}]
# => ...done.

# on rabbit2
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit2 ...
# => [{nodes,[{disc,[rabbit@rabbit2]}]},{running_nodes,[rabbit@rabbit2]}]
# => ...done.

# on rabbit3
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit3 ...
# => [{nodes,[{disc,[rabbit@rabbit3]}]},{running_nodes,[rabbit@rabbit3]}]
# => ...done.
複製代碼
  • 加入集羣
# on rabbit2
rabbitmqctl stop_app
# => Stopping node rabbit@rabbit2 ...done.

rabbitmqctl reset
# => Resetting node rabbit@rabbit2 ...

rabbitmqctl join_cluster rabbit@rabbit1
# => Clustering node rabbit@rabbit2 with [rabbit@rabbit1] ...done.

rabbitmqctl start_app
# => Starting node rabbit@rabbit2 ...done.
複製代碼
  • 查看狀態
# on rabbit1
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit1 ...
# => [{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
# => {running_nodes,[rabbit@rabbit3,rabbit@rabbit2,rabbit@rabbit1]}]
# => ...done.
複製代碼
  • user
systemctl start rabbitmq-server
rabbitmq-plugins enable rabbitmq_management
rabbitmqctl add_user admin xxxxxx
rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*"
rabbitmqctl set_user_tags admin administrator
複製代碼
  • 監控
docker run -d  -e RABBIT_URL=http://{{內網Ip}}:15672 -e RABBIT_CAPABILITIES=bert,no_sort -e RABBIT_USER=admin  -e RABBIT_PASSWORD=xxx  -e PUBLISH_PORT=9419 -p 9419:9419  kbudde/rabbitmq-exporter
複製代碼
相關文章
相關標籤/搜索