http://blog.csdn.net/mra__s__/article/details/55011530
理解消息通信
一、 消息通信的概念--消費者、生產者和代理
生產者創建消息,消費者接受這些消息。你的應用程序可以作為生產者,向其他應用程序發送消息,或者作為一個消費者,接收消息。也可以在兩者之間進行切換。不過在此之前,它必須先建立一條信道(channel)。不論你是發布消息、訂閱隊列或是接受消息都是通過信道完成。
二、 AMQP元素--交換器、隊列和綁定
從概念上講,AMQP消息路由必須有三部分:交換器、隊列和綁定。生產者把消息發布到交換器上;消息最終到達隊列,并被消費者接受;綁定決定了消息如何從路由器路由到特定的隊列。在研究交換器和綁定之前,需要先理解隊列的概念和工作原理。如下圖:

消費者通過以下兩種方式從特定隊列中接收消息:
(1) 通過AMQP的base.consumer命令訂閱。這樣做會將信道置為接收模式,直到取消對隊列的訂閱為止。
(2) 有些時候,你只想從隊列中獲取單條消息而不是持續訂閱。向隊列請求單條消息是通過AMQP的base.get命令實現的。大致上講,base.get命令會訂閱消息,獲取單條消息,然后取消訂閱。消費者理應始終使用base.consumer來實現高吞吐量。
A: 當有多個消費者訂閱到同一個隊列上是,消息是如何發布的:
Q: 隊列收到的消息將以循環(round-robin)的方式發送給消費者,每條消息只會發送給一個消費者。消息確認接收機制:消費者必須通過AMQP的base.ask命令顯式的向RabbitMQ發送一個確認消息,或者在訂閱到隊列的時候就將base.ask參數設置成true。消費者對消息的確認和告訴生產者消息已經被接收這兩件事毫不相關。
如何創建隊列。生產者和消費者都能使用AMQP的base.declare命令創建隊列。如果消費者在同一條信道上訂閱了另一條對列的話,就無法再聲明隊列了。則必須先取消隊列,將信道置為“傳輸”模式。
隊列設置了一些有用的參數:
1.exlusion--將參數設置成true后隊列將變為私有,限制一個隊列中只能有一個消費者。
2.auto-delete--將參數設置為true后,最后一個消費者取消訂閱之后隊列將自動移除。
聯合:交換器和綁定。
Q: 消息是如何到達隊列的呢?
A: 路由鍵規則來指定消息從路由器到哪個隊列。
Q: 那它是如何處理投遞到多個隊列的情況呢?
A: 協議中定義的不同類型交換器發揮了作用。一共四種類型:direct、fanout、topic和header。
direct:如果路由鍵匹配的話,消息就被投遞到對應的隊列。
base_publish($msg,'默認交換器','隊列名稱');

fanout:當你發送一條消息到fanout路由器時,他會把消息投遞給所有附加在此交換器上的隊列。可以輕而易舉地添加應用程序的功能。
base_publish($msg,'logs-exchange','error.msg-inbox');

topic:跟direct比較相像,有一些通配規則。單個“.”把路由分成幾部分,“*”匹配特定位置的任意文本,“#”匹配所有規則。
queue_bind('msg-inbox-errors','logs-exchange','error.msg-inbox');
queue_bind('msg-inbox-errors','logs-exchange','*.msg-inbox');
queue_bind('all-logs','logs-exchange','#');

三、 虛擬主機
虛擬主機vhost是AMQP概念的基礎,你必須在連接時進行指定。RabbitMQ包含了開箱即用的默認虛擬主機"/",因此使用非常簡便。vhost之間是絕對隔離,保障了隊列和交換機的安全性,因此消息路由的組件也無法進行交互。
rabbitmqctl add_vhost[vhost_name]
rabbitmqctl delete _vhost[vhost_name]
四、 消息持久化
重啟rabbitmq服務器后,那些隊列和交換器就都消失了,原因在于每個隊列和交換器的durable屬性,該屬性默認情況為false。如果需要持久化,單純將隊列和交換器的durable屬性設置為true是不夠滴。消息發布之前,通過把它的“投遞模式”(delivery mode)選項設置為2來把消息標記為持久化。代價則是消耗性能,雖然重啟RabbitMQ服務器后隊列和交換器能恢復。
五、 一條消息經歷從生產者到消費者的生命周期
發布者需要完成的任務:1.連接到RabbitMQ。2.獲取信道。3.聲明交換機。4.創建消息。5.關閉消息。6.關閉信道。7.關閉連接。
消費者需要執行的任務:1.連接到RabbitMQ。2.獲取信道。3.聲明交換機。4.聲明隊列。5.把隊列和交換機綁定起來。6.消費消息。7.關閉信道。8.關閉連接。
使用發送方確認模式來確認投遞。
運行和管理RabbitMQ
一、 服務器管理—啟動和停止節點
運行子系統:rabbitmq安裝目錄下找到./sbin目錄,運行./rabbitmq-server。通過日志查看運行情況,日志目錄/var/log/rabbitmq/下。以守護程序的方式在后臺運行:./rabbitmq-server detached,至此rabbitmq服務啟動成功。
當運行rabbitmq連接到控制臺時,你按下CTRL+C組合鍵后你猜是哪個..
在rabbitmq安裝目錄下運行./sbin/rabbitmqctl stop來干凈地關閉。
rabbitmq配置文件目錄在/etc/rabbitmq/rabbitmq.config。
二、 權限配置
RabbitMQ權限工作原理:用戶可以為連接到RabbitMQ主機的應用程序設計不同級別的權限(讀、寫和“/”或配置)。
管理用戶:在RabbitMQ中,用戶是訪問控制的基本單元。針對一到多個vhost,其可以被賦予不同級別的訪問權限,并使用標準的用戶名/密碼對來認證用戶。對用的增加、刪除以及列出列表,都非常簡單。這些操作都是通過rabbitmqctl完成的。
添加用戶:rabbitmqctl add_user username password
刪除用戶:rabbitmqctl delete_user username
用戶列表:rabbitmqctl list_users

設置權限:rabbitmqctl set_permissions –p sycamore \ cashing-tier “.*” “.*” “.*”
–p sycamore:告訴set_permissions條目應該應用在哪個vhost上面。
cashing-tier:被授予權限的用戶。
“.*” “.*” “.*”:這些是授予的權限。這些值分別映射到配置、寫和讀。
移除權限:rabbbimqctl clear_permissions –p sycamore cashing-tier
權限列表:rabbitmqctl list_user_permissions cashing-tier
三、 使用統計
其中經常看到的-p選項,它指明了虛擬主機和路徑信息。
rabbitmqctl list_queues -p sycamore 列出虛擬主機為sycamore的隊列列表
list_queues [-p Vhost_Path] [<QueueInfoItem>]
rabbitmqctl list_exchanges
list_exchanges [ExchangeInfoItem]
rabbitmqctl list_bindings
理解RabbitMQ日志,LOG_BASE=/var/log/rabbitmq
四、 RabbitMQ和Erlang問題疑難解答
由badrpc、nodedown和其他Erlang引起的問題
1. Erlang Cookie
使用rabbitmqctl命令時常出現一些莫名錯誤。先理解下rabbitmqctl的工作原理。rabbitmqctl命令先啟動Erlang節點,并從那個使用Erlang分布式系統嘗試連接RabbitMQ節點。要完成這項工作需要兩樣東西:合適的Erlang Cookie和合適的主機名稱。
Q: 那么什么是Erlang Cookie呢?
A: Erlang節點通過交換作為秘密令牌的Erlangcookie以獲得認證。Erlang將令牌存儲于home目錄下的.erlang.cookie文件中
2. Erlang節點
當你啟動Erlang節點時,你可以給它兩個互斥的節點名選項,name和sname。
當你想讓rabbitmqctl能夠連上RabbitMQ時,你必須使得這些參數兩邊都能匹配(rabbit@hostname)。
3. Mnesia和主機名
RabbitMQ使用Mnesia存儲隊列、交換器、綁定等信息。RabbitMQ啟動時做的一件事就是啟動Mnesia數據庫。如果啟動Mnesia失敗,則RabbitMQ也會跟著失敗。而導致Mnesia失敗的原因大致有二:第一個也是最常見的MNESIA_BASE目錄的權限問題。另一個常見問題是讀取表格失敗。如果主機名更改了,或是服務器運行在集群模式下,無法在啟動的時候連接到其他節點,都會導致啟動失敗。
4. Erlang故障排除技巧
以test作為節點名啟動Eralng節點:erl sname test。
執行node()函數會展示--Erlang中方括號為界的列表--你連接上的節點列表。
通過使用rpc:call,同時提供節點、模塊、函數和參數作為入參,你可以在遠程rabbit上執行其他參數以獲取不同的信息。
解決Rabbit相關問題:編碼與模式
一、 面向消息通信來設計應用程序
1. 異步狀態思維(分離請求和動作)
2. 提供擴展性:沒有負載均衡器的世界
3. 使用AMQP來解耦應用程序最大好處:免費的API,語言不會約束消息通信。
二、 消息通信模式
解決耗時的任務和整合用不同語言編寫的應用程序。這兩個看似有不同的問題,但卻有著共同的本質:解耦請求和操作。或者換種說法,這兩個問題均需要從同步編程模式轉向異步編程模式。
三、 發后即忘模型
匹配該模式的兩種一般類型的任務
1. 批處理(batchprocessing)--針對大型數據集合的工作和轉換。這種類型的任務可以構建為單一的任務請求,或者多個任務對數據集合的獨立部分進行操作。
2. 通知(notifications)--對發生事件的描述。內容可以是消息的日志,也可以是真實的報告通知給另一個程序或者是管理員。
這兩個例子符合我們之前提到的兩種類別:第一個是告警框架(發送告警)。另一個是將單張圖片上傳并將其轉換成眾多圖片格式和尺寸(并行處理)。
四、 用RabbitMQ實現RPC
1. 私有隊列和確認發送。
2. 使用reply_to來實現簡單的jsonRPC
集群并處理失敗
一、 RabbitMQ集群架構
RabbitMQ最優秀的功能之一就是其內建集群。同時能夠將集群在5分鐘內構建并運行起來。
RabbitMQ內建集群的設計用于完成兩個目標:允許消費者和生產者在Rabbit節點奔潰的情況下繼續運行,以及通過添加更多的節點來線性擴展消息通信吞吐量。
Q: RabbitMQ是如何記錄你所有使用過的各種基礎構件,同時他們又如何裝配成一個消息通信服務器的呢?
A: RabbitMQ會始終記錄以下四種類型的內部元數據:
1. 隊列元數據--隊列名稱和屬性(是否可持久化,是否自動刪除)
2. 交換器元數據--交換器名稱、類型和屬性(可持久化等)
3. 綁定元數據--一張簡單的表格展示了如何將消息路由到隊列
4. vhost元數據--為vhost內的隊列、交換器和綁定提供命名空間和安全屬性。
我們深入到集群節點和他們如何存儲元數據前,首先理解在集群環境中隊列和交換器的行為。
1. 集群中的隊列。
2. 分布交換器。
3. 是內存節點還是磁盤節點。
二、 在你的筆記本上搭建集群
在筆記本上創建三個節點,然后將三個節點集群,具體操作可以參考之前兩篇文章。
三、 使用物理服務器創建集群
分布在不同的服務器上創建不同的節點,將不同節點進行集群。

四、 升級集群節點
獨立系統中升級節點只需解壓新版本,然后運行即可,舊的數據也將會保留。如果是集群節點,需要備份配置信息后,關閉所有生產者等待消費者消費完隊列中的所有信息(rabbitmqctl觀察隊列狀態)。現在,關閉節點,并解壓新版本到RabbitMQ到現有的安裝目錄。
五、 與鏡像隊列一起工作
當加入鏡像隊列后,信道負責將消息路由到合適的隊列。

鏡像隊列是如何影響事務和發送方確認模式的?
1. 鏡像隊列主拷貝故障時,從拷貝變成主拷貝。
2. 如果鏡像隊列失去一個從節點的話,則附加在鏡像隊列的任何消費者都不會注意到這一點。
3. 如果客戶端庫不能支持消費者取消通知的話,你應該避免使用鏡像隊列。
從故障中恢復
一、 理解負載均衡
負載均衡將服務器集群IP封裝,提供暴露成統一接口。通過將負載均衡器放置在Rabbit的前端,你就可以讓它來處理節點選擇、故障服務器檢測以及負載分布這些復雜的事情了。

二、 安裝并配置HAProxy來為Rabbit做負載均衡
選擇使用HAProxy的原因:它是免費的,而且非常可靠,并且為各種站點處理高負載,例如:StackOverFlow。同時,它可以運行在幾乎所有的基于UNIX的平臺上,并且非常容易配置。
1. 安裝HAProxy
2. 配置HAProxy
以上兩步自己度娘。
三、 重連并從故障中恢復
現在開發系統上運行著負載均衡器,我們準備深入探索如何使用它來為消息通信應用程序植入故障轉移和快速恢復的能力。
1. 如果我重新連接到新的服務器,那么我的信道以及其上的所有消費循環會怎樣呢?它們現在都失效了。你必須對它們進行重建。
2. 當我進行重連的時候,我能否假設所有的交換器、隊列和綁定仍然存在于集群之中?我能否重連之后立即開始從隊列消費呢?
Warren和Shovel:故障轉移和復制
一、 理解主/備方式(warren)
集群迫使你不得不在以下兩者之間做權衡:所有節點表現得像獨立單元來分布負載的優點,但是在故障節點恢復前無法使用可持久化隊列的缺點。這正是warren和Shovel的用武之地。
二、 使用負載均衡器創建warren
基于warren的負載均衡器的HAProxy配置。基于負載均衡器來做故障轉移,最重要的是可以確保當故障轉移發生時,你無須擔心RabbitMQ無法在備用節點啟動,因為它已經運行了。由于Rabbit始終在主節點和備用節點上運行,因此你們可以始終對它們進行監控。如果備機在派上用場之前就變為不可用的話,你在第一時間就能發現。這通過使用共享存儲warren是無法做到的。
三、 使用Shovel構建遠距離復制
在掌握了集群和warren之后,你就能處理故障并在數據中心之上進行擴展了,但是當你需要在不同的數據中心的Rabbit間復制消息時,改怎么辦呢?這時,我們就需要Shovel了。
1. 給Rabbit裝備Shovel:Shovel插件介紹。
2. 安裝Shovel
3. 配置并運行Shovel
從Web端管理RabbitMQ
一、 Managent插件相對于rabbitmqctl腳本的優勢
方便、簡潔、功能齊全、瀏覽多方面同時監測。
二、 啟用RabbitMQ Management插件
rabbitmq-plugins enable rabbitmq-management
三、 Management插件功能

四、 從Web控制臺來管理用戶、隊列和交換器
在web控制臺上做如下操作:(具體結合界面應用)
1. 創建用戶
2. 管理用戶的權限
3. 列出隊列信息
4. 創建隊列
五、 Management插件REST接口介紹
1. 通過使用REST API,你可以輕松自動化那些到目前為止只能通過圖形化界面完成的任務。
2. CLI管理:一種更簡潔的方式。
3. 安裝rabbitmqadmin腳本。
4. 應用rabbitmqadmin腳本。
使用REST API控制Rabbit
一、 Rabbit REST API的限制和功能
不管用API創建隊列還是設置權限,每當使用PUT或POST動作的時候,都需要將函數參數編碼為JSON格式的哈希表,然后添加到請求正文中。你可以通過瀏覽器訪問http://localhost:55672/api來查看目前大多數(以及完整的)API列表和支持的HTTP動作。
二、 訪問消息通信數據統計和計數器
Rabbit Management API使得你可以在任何能夠訪問網絡的地方監控并控制Rabbit。具體詳情看此書,代碼來控制的。
三、 自動化創建用戶和虛擬主機
我們在部署應用時,就使用了相似的腳本來自動化創建用戶。通過構造這段腳本,你不僅學習了如何使用Management API來展示條目,還學習了如何展示條目列表,以及如何創建和刪除這些條目。你這樣將這些概念應用到處理其他條目/資源類型(用戶、隊列、交換器、連接、權限等)。具體腳本看此書。
監控
一、 編寫Nagios健康檢測的基礎
Nagios健康檢測是一個獨立程序,它在運行時監控服務并在程序停止運行時退出代碼來指示服務的健康狀態。從技術上來講,你甚至不需要Nagios來運行健康檢測--你可以在任何時候通過命令行執行并手工觀測輸出。Nagios健康檢測可以用任何語言編寫,可以是Python程序,甚至是BASE腳本。
二、 使用AMQP和REST API來監控Rabbit內部狀態
構建的AMQP健康檢測,當下列任務條件之一為真時,該檢測程序會返回一個critical狀態
1. RabbitMQ沒有響應TCP連接。
2. 當發送AMQP命令時,Pika在接收到響應之前超時了。
3. 當構造AMQP信道時,遇到了協議錯誤。
僅當這些狀態檢測都為false時,健康檢測程序才會返回OK狀態。
基于API的健康檢測,aliveness-test,顧名思義,使用三個步驟來驗證Rabbit服務器是否健康:
1. 創建一個隊列來接收測試消息。
2. 用隊列名稱作為消息路由鍵,將消息發往默認交換器。
3. 當消息到達隊列的時候就消費該消息;否則就報錯。
三、 使用Rabbit可用并且能夠進行響應
有許多原因會致使RabbitMQ使用太多的內存,并達到Rabbit配置的最大內存上限。以下是最常見的幾種原因:
1. 應用程序有缺陷,消費消息之后忘記向RabbitMQ發回確認消息。這在高容量環境下,會導致成千上萬條的消息堆積并耗盡Rabbit的內存。
2. 應用程序使用RabbitMQ將大型數據(譬如圖像)路由到處理節點。用不了多少張100MB大小的圖像就可以將只有8GB內存大小的服務器內存耗盡。
3. 使用了最新RabbitMQ版本中的新功能,但是該功能有個BUG會導致緩慢的內存泄漏。
四、 觀察隊列狀態以盡早檢測消費者問題
監控消費者是否正確運作的方式就是通過監控隊列的消息總數,并在總數超過設定的warning或者critical閾值時觸發警告。以下通過兩種方式來監控隊列消息總數:
1. 使用AMQP的queue_declare()命令,設置passive=true參數來重新聲明一個已存在的隊列。當你在AMQP中聲明一個隊列時,如果將passive設置為true的話,那么該命令返回的結果中將包含隊列消息的總數。
2. 利用我們的老朋友RabbitManagement API來總隊列上拉取數據統計,其中就有隊列當前的消息總數。
五、 檢測消息通信結構中不合需求的配置更改
確保消費者正常工作,檢查消息通信結構配置問題:
1. 通過AMQP監控隊列等級。
2. 使用REST API來監控隊列級別。
3. 建立隊列的消息計數基準經驗法則。
提升性能,保障安全
一、 交換器、隊列和綁定的內存占用
根據數據顯示隊列、交換器和綁定的內存占用很小,另一個施加在RabbitMQ上的硬性限制是每個Erlang節點的最大Erlang進程數。Erlang應用程序在整個生命周期中會多次創建并銷毀進程。
二、 消息持久化和磁盤I/O
當發布消息時,你需要決定丟失其中的任何消息對你來說是否可以接受,這決定了deleverymode設置的值為1(非持久化)還是2(持久化)的問題。
在消息消費過程中你該如何配置,加快消息投遞的設定是no-ack標記,你可以在隊列訂閱時指明。
路由算法和綁定規則,三種不同類型的交換器:direct、fanout和topic。每種交換器類型代表了服務器實現的特定路由算法。綁定規則的路由鍵模式將更占用內存。

本節介紹了不同的算法和消息發布訂閱設置如何影響整個系統的速度,以及像auto-ack模式標記設定能在很大程度上影響系統性能。
三、 RabbitMQ的SSL連接及設置私鑰架構
1. SSL證書。
2. 設置證書頒發機構。
3. 生成根證書。
4. 生成服務器端證書。
5. 生成客戶端證書。
6. 啟用RabbitMQ的SSL監聽。
7. 測試你的RabbitMQ SSL設置。
聰明的Rabbit:擴展RabbitMQ
一、 安裝RabbitMQ插件
我可以通過安裝插件的方式來解決:
1. 支持AMQP以外的協議。
2. 不同的認證機制(LDQP,自定義數據庫)。
3. 消息復制。
4. 新的交換器和路由算法。
5. 消息日志和審計。
如果你想啟用的插件不是服務器發行的一部分該怎么辦呢?首先,你得下載插件的.ez文件到RabbitMQ安裝目錄的plugins文件夾下,之后像往常一樣運行./rabbitmq-plugins enable plugin_name命令即可。
二、 實現自定義交換器插件
1. 將交換器注冊到Rabbit。
2. 實現交換器behaviour。
3. 編譯自定義交換器。
4. 測試你的插件。
posted on 2017-12-15 14:09
思月行云 閱讀(1637)
評論(0) 編輯 收藏 引用 所屬分類:
分布式\MQ