本系列是「rabbitmq實戰:高效部署分布式訊息佇列」書籍的總結筆記。前兩篇介紹了rabbitmq在可用性、監控方面的考慮,這是基礎保障,因為在某些場景下是不容許丟失訊息的,但它和效能往往是對立的,需要根據業務場景做取捨。
通過介紹,你會了解到:
有很多因素影響rabbitmq投遞訊息的速度,包括訊息持久化、路由演算法、繫結數目、以及訊息確認策略等,下面分別來介紹。
訊息持久化
當發布訊息時,需要決定丟失其中的任何訊息是否可以接受,如果可以接受,可以將delivery-model設定為1,訊息就不會持久化到硬碟了。
訊息確認
當消費訊息時,可以在佇列訂閱時,通過設定no-ack標記加快訊息投遞,如果設定為true,伺服器就會在訊息傳送給客戶端後自動將其出隊。
這樣,處理完訊息之後就無須再傳送確認訊息回伺服器了,能極大地加快消費者消費訊息,但由於某些原因連線中斷了,或客戶端應用程式發生故障了,訊息就永遠訊息了。
路由演算法和繫結規則
前面介紹了3種型別的交換器:direct、fanout、topic,每種交換器代表了伺服器實現的特定路由演算法,會根據訊息的路由鍵以及佇列與交換器之間的繫結來選擇佇列。
在伺服器端,交換器和繫結作為記錄條目儲存在mnesia資料庫中,當匹配訊息路由鍵時,會嘗試查詢對應路由鍵的繫結。
fanout交換器在路由訊息的時候,會忽略路由鍵,不需要進行查詢。direct只有乙個繫結,也會比較快,topic儲存的路由資訊比較複雜,由於路由鍵可以包含以點分隔的多個詞,所以匹配訊息路由鍵不僅僅是簡單字串的匹配,也會占用更多記憶體。
rabbitmq實現了trie樹資料結構用來儲存繫結路由鍵模式,以支援快速查詢,關於這種資料結構,我之前沒接觸過,據說比桶狀雜湊表還快,後面專門寫一篇介紹這個資料結構吧。
投遞訊息
在交換器找到訊息需要路由的目的地之後,會將目的地列表返回給rabbit_router,之後會將訊息的副本投遞到每乙個目的地,如果發布的訊息中mandatory和immediate標記設定為false,這個過程會以非同步方式執行,從客戶端角度看,伺服器會變得很快,否則會同步投遞。
當mandatory標誌位設定為true時,如果exchange根據自身型別和訊息routekey無法找到乙個符合條件的queue,那麼會呼叫basic.return方法將訊息返還給生產者,當mandatory設為false時,出現上述情形broker會直接將訊息扔掉。假如找到了投遞的佇列且有消費者準備好接收訊息,如果隊列為空,訊息會直接傳送給消費者,不會經過佇列這一步,會極大提公升速度,所以制定容量規劃並計算訊息的進出率時,應盡可能讓佇列保持為空,如果消費滯後導致佇列填滿的化,伺服器會收到記憶體告警,並將訊息刷出磁碟。當immediate標誌位設定為true時,如果exchange在將訊息route到queue(s)時發現對應的queue上沒有消費者,那麼這條訊息不會放入佇列中。當與訊息routekey關聯的所有queue(乙個或多個)都沒有消費者時,該訊息會通過basic.return方法返還給生產者。
還有個引數要注意:auto-ack,消費者接收到訊息後,會立刻確認訊息,而不用等到邏輯處理好。
以上說的提高速度的方法大部分都會犧牲可用性,要根據不同的業務場景進行平衡。在設計應用程式的時候,會有兩個基本限制:選擇的技術允許做什麼,以及當前硬體設定允許做什麼。上面討論了第一點:不同訊息路由和分發演算法如何影響設計決策。關於第二點,需要考慮amqp的元素需要多少記憶體,以及erlang vm對可以建立的程序總數的硬體限制。
記憶體考慮
1.佇列元資料
2.交換器元資料
3.繫結元資料
乙個持久化佇列繫結到乙個瞬時交換器會導致在rabbit_semi_durable_router表上建立條目。
erlang程序計數
可以在節點啟動時指定erlang節點上能執行的最大erlang程序數,預設設定是每個erlang節點1048576,即2^20個。
erlang應用程式在整個生命週期中會多次建立並銷毀程序。比如,rabbitmq接收到amqp客戶端的tcp連線時,會建立乙個程序進行管理該連線,同時,會有很多erlang程序來處理訊息儲存的邏輯。
主要通過以下事件來增加程序數:到伺服器的新連線、建立新的通道以及佇列宣告。一條新的連線會建立四個新的程序,乙個新的通道也會建立四個新的程序,佇列的開銷最小,每個佇列乙個程序。
有些訊息,想以一種安全的方式進行傳輸,可以使用ssl協議在訊息通訊終端傳輸資料,rabbitmq預設支援ssl,只需要配置相應的證書,使用openssl庫進行設定和操作。
只需要修改下rabbitmq的配置即可,在rabbitmq.config中新增ssl_listeners和ssl_options配置項:
[,,
,,,]}
]}]
配置中指定了ca的證書,服務端的證書,以及服務端的秘鑰。
require_once(__dir__ . '/../amqp.inc');
define('host', 'localhost');
define('port', 5671);
define('user', 'guest');
define('pass', 'guest');
define('vhost', '/');
define('amqp_debug', true);
define('certs_path',
'/path/to/ca/folder/');
$ssl_options = array(
'cafile' => certs_path . '/rmqca/cacert.pem',
'local_cert' => certs_path . '/phpcert.pem',
'verify_peer' => true
);$conn = new amqpsslconnection(host, port, user, pass, vhost, $ssl_options);
function
shutdown
($conn)
register_shutdown_function('shutdown', $conn);
while(1){}
客戶端**指定了ca根證書和客戶端證書和秘鑰,phpcert.pem是客戶端證書、秘鑰、ca根證書的合併檔案。
RabbitMQ實戰 效能和安全
前兩篇介紹了rabbitmq在可用性 監控方面的考慮,這是基礎保障,因為在某些場景下是不容許丟失訊息的,但它和效能往往是對立的,需要根據業務場景做取捨。通過介紹,你會了解到 對速度的考慮 有很多因素影響rabbitmq投遞訊息的速度,包括訊息持久化 路由演算法 繫結數目 以及訊息確認策略等,下面分別...
RabbitMQ實戰 訊息通訊模式和最佳實踐
本系列是 rabbitmq實戰 高效部署分布式訊息佇列 書籍的總結筆記。通過介紹,你會了解到 主要從非同步狀態思維 處理能力擴充套件性 整合複雜度方面,說明面向訊息通訊的好處。非同步狀態思維 當將訊息通訊整合到應用程式時,開發模式將從同步模型變為非同步模型,rabbitmq提供了不同的方法,允許我們...
RabbitMQ實戰 訊息通訊模式和最佳實踐
本系列是 rabbitmq實戰 高效部署分布式訊息佇列 書籍的總結筆記。通過介紹,你會了解到 主要從非同步狀態思維 處理能力擴充套件性 整合複雜度方面,說明面向訊息通訊的好處。非同步狀態思維 當將訊息通訊整合到應用程式時,開發模式將從同步模型變為非同步模型,rabbitmq提供了不同的方法,允許我們...