RabbitMQ in Action(一)

  • RabbitMQ采用Erlang編寫,需安裝語言庫才能運行RabbitMQ代理服務器。
  • AMQP:高級消息隊列協議。
  • Github代碼

理解消息通信

生產者和消費者

生產者創建消息并創建標簽,然后發布到代理服務器RabbitMQ。

消息包含兩部分內容

  • 有效載荷:需傳輸的數據,可以是任何內容。
  • 標簽:用于描述有效載荷,并指定誰將獲得消息的拷貝。

消費者連接到代理服務器,并訂閱到隊列。

消費者只會接收到有效載荷。在消息路由過程中,消息的標簽并沒有隨有效載荷一同傳遞。

建立RabbitMQ連接

  1. 創建應用程序→RabbitMQ代理服務器TCP連接。
  2. 在TCP連接上創建信道,AMQP命令也是通過信道發送的。每條信道都會被分配一個唯一的ID。

隊列

AMQP消息路由三要素

  • 交換器
  • 隊列
  • 綁定

消費者通過以下兩種方式從特定的隊列中接收消息

  1. 連續獲得:通過AMQP的basic.consume命令訂閱。這樣做會將信道置為接收模式,直到取消對隊列的訂閱為止。訂閱了消息后,消費者在消費|拒絕最近接收的消息后,就能從隊列中自動接收下一條消息。
  2. 獲得單條:通過AMQP的basic.get命令訂閱。basic.get會訂閱消息,獲得單條消息,然后取消訂閱。

消費者接收到的每一條消息都必須進行確認,確認后RabbitMQ才會從隊列移除該消息

  1. 通過AMQP的basic.ack命令顯示地向RabbitMQ發送確認。
  2. 訂閱到隊列時設置auto_ack參數為true,則消費者接收到消息,RabbitMQ會自動視其確認了消息。

拒絕接收消息

  1. 把消費者從RabbitMQ服務器斷開連接。
  2. 使用AMQP的basic.reject命令(RabbitMQ2.0.0+)。其參數requeue可指定該消息是否發送給下一個消費者進行處理。在新版本中,該參數置為false會讓消息進入死信隊列,被拒絕而不重入隊列的消息,可用于檢測問題。

聲明隊列

  • 使用AMQP的queue.declare命令來創建隊列。
  • 若消費者在同一條信道上訂閱了另一個隊列,需先取消訂閱并將信道置為傳輸模式。
  • 消費者創建隊列時需指定隊列名稱,若未指定Rabbit會分配一個隨機名稱并在queue.declare命令的響應中返回。
  • 參數說明
  • exclusive:是否私有,可用于限制一個隊列只有一個消費者。
  • auto-delete:是否自動移除,可用于只有一個消費者服務。結合exclusiveauto-delete,可實現當消費者斷開連接時,則移除隊列。
  • passive:檢測是否已存在隊列,存在則成功返回;否則不創建隊列且返回一個錯誤。
  • 聲明一個已存在的隊列
  • 參數完全匹配現存的隊列,Rabbit什么都不做,并成功返回。參數不匹配則會失敗。

生產者還是消費者來創建隊列

發送出去的消息如果路由到了不存在的隊列,Rabbit會忽略它們

  • 避免消息進入黑洞而丟失,則生產者和消費者都應該嘗試去創建隊列。
  • 可忽略消息進入黑洞而丟失,或者自定義方法來重新發布未處理消息,則可只讓自己的消費者來聲明隊列。

交換器和綁定

  • 消息通過路由鍵綁定到交換器,服務器會根據路由將消息從交換器路由到隊列。
  • 如果路由的消息不匹配任何綁定模式,則消息將進入黑洞。

使用交換器和綁定的優點

  • 完成不同的使用場景
  • 對于消息的生產者來說,它不需要關心服務器的另一端隊列和消費者的邏輯。

交換器四種類型

  • direct:若路由鍵匹配,消息就被投遞到相應的隊列。交換器名稱為空白字符串。
  • fanout:會將收到的消息廣播到所有綁定的隊列中。
  • topic:可讓來自不同源頭的消息到達同一個隊列。
  • headers:允許匹配AMQP消息的header而非路由鍵,headers和direct交換器完全一致,但性能會差很多,幾乎不用。

隊列綁定到交換器可使用通配符

  • .可將路由鍵分割成若干個部分
  • *匹配任意文本
  • #匹配所有規則,沒有分割概念,將.視為關鍵字的匹配部分

虛擬主機和隔離

虛擬主機vhost

  • 默認vhost:/
  • 默認用戶和密碼:guest
  • Rabbit管理工具:RabbitMQ安裝目錄下的rabbitmqctl,該命令不帶參數則顯示幫助信息。
  • 擁有自己的隊列,交換器和綁定。
  • 擁有自己的權限機制,vhost之間是絕對隔離的。
  • 可只運行一個Rabbit,然后按需啟動若干個vhost。
  • 在RabbitMQ集群上創建vhost時,整個集群上都會創建該vhost。

rabbitmqctl參數

  • -n rabbit@[server_name|ip]:指定遠程節點,默認為本地。需確保運行Rabbit節點的服務器和運行rabbitmqctl的工作站安裝了相同的Erlang cookie。

管理vhost

  • 創建vhostrabbitmqctl add_vhost [vhost_name]
  • 刪除vhostrabbitmqctl delete_vhost [vhost_name]
  • 列出Rabbit服務器上的vhostrabbitmqctl list_vhosts

持久化策略

設置參數實現持久化

  • 消息投遞模式設置為2(持久化)
  • 發送到持久化的交換器
  • 到達持久化的隊列
  • 隊列和交換器的durable屬性:是否持久化。默認fasle。
  • 消息的投遞模式設值為2:標記成持久化。
  • 持久化方式實現:將持久化消息寫入持久化日志文件。
  • 持久化消息在RabbitMQ內建集群環境下工作得并不好。
  1. 持久化消息→持久化交換器:Rabbit會在消息提交到日志文件后才發送響應。
  2. 持久化消息→非持久化隊列,則會將該消息從日志中移除。

AMQP事務

優點:

  • 填補了生產者發布消息和RabbitMQ將它們提交到磁盤過程中差生錯誤的漏洞。

缺點:

  • 會降低大約2~10倍的消息吞吐量。
  • 會使生產者應用程序產生同步。

發送方確認模式

需要將信道置為confirm模式,只能通過重新創建信道來關閉該設置。

優點:

  • 異步執行
  • 更加輕量級,對Rabbit性能的影響幾乎可以忽略不計。

消息的生命周期

生產者

需要完成的任務

  1. 創建RabbitMQ連接
  2. 獲取信道
  3. 聲明交換器
  4. 創建消息
  5. 發布消息
  6. 關閉信道
  7. 關閉RabbitMQ連接
  8. 代碼展示

消費者

需要完成的任務

  1. 創建RabbitMQ連接
  2. 獲取信道
  3. 聲明交換器
  4. 聲明隊列
  5. 隊列和交換器綁定
  6. 消費信息
  7. 關閉信道
  8. 關閉RabbitMQ連接
  9. 代碼展示

*發送方確認模式進行確認投遞

  • 若同時擁有眾多運行的信道,則需要為每條信道維護一個內部的ID計數器。
  • 代碼展示

Rabbit的運行管理

  • Erlang節點和Erlang應用程序。
  • 節點:指代RabbitMQ服務器實例。
  • JVM:一個實例一個應用程序。
  • Erlang:一個節點可同時運行多個應用程序。
  • 如果應用程序崩潰了,節點會自動嘗試重啟應用程序。
  • RabbitMQ節點:通常指RabbitMQ應用程序和其所在的Erlang節點。

管理節點

  • 啟動Erlang節點和Rabbit應用程序:rabbitmq -server,參數-detached:后臺啟動。
  • 停止節點(應用程序和節點同時關閉):rabbitmqctl stop,參數-n rabbit@[hostname]可指定遠程節點。
  • 只停止RabbitMQ程序:rabbitmqctl stop_app

Rabbit配置文件

rabbitmq.config

  • Erlang數據結構
  • mnesia:Mnesia數據庫配置選項,Mnesia是RabbitMQ用來存儲交換器和隊列元數據的。Mnesia配置選項
  • rabbit:Rabbit特定的配置選項
  • 配置文件不能完成對RabbitMQ的訪問控制

管理權限

單個用戶可以跨越多個vhost進行授權。

用戶管理

  • 創建用戶:rabbitmqctl add_user username password
  • 刪除用戶:rabbitmqctl delete_user username,訪問控制條目一并刪除。
  • 列出用戶:rabbitmqctl list_users
  • 修改用戶密碼:rabbitmqctl change_password username new_password

Rabbit權限系統

AMQP操作到RabbitMQ權限的映射關系表

  • 創建權限rabbitmqctl set_permissions -p vhost_name username ".*" ".*" ".*",參數-p指定vhost(默認為/),后面三個正則式參數分別對應:配置,寫,讀權限。
  • 列出指定vhost的權限信息rabbitmqctl list_permissions -p vhost_name
  • 刪除權限rabbitmqctl clear_permissions -p vhost_name username
  • 列出用戶在Rabbit上的所有權限信息rabbitmqctl list_user_permissions username

列出隊列,交換器和綁定相關信息

列出隊列以及隊列信息

  • 列出隊列rabbitmqctl list_queues -p vhost_name,參數-p指定vhost(默認為/)
  • 列出隊列其他信息rabbitmqctl list_queues queue_info_item...,queue_info_items選項列表

列出交換器信息

  • rabbitmqctl list_exchanges:默認返回交換器名稱和類型。
  • rabbitmqctl list_exchanges exchange_info_item...:指定返回其他信息。exchange_info_items選項列表

列出綁定信息

  • rabbitmqctl list_bindings,參數-p可指定vhost(默認為/),默認返回的信息每行包含:交換器名稱,隊列名稱,路由鍵和參數。

RabbitMQ日志

LOG_BASE環境變量

  • rabbitmq-server:LOG_BASE=/var/log/rabbitmq
  • rabbit-sasl.log:Erlang運行相關信息。
  • rabbit.log:Rabbit運行相關信息,如網絡流量,用戶,交換器隊列等。

輪換日志

  • rabbitmqctl rotate_logs suffix:切換新日志文件,原日志文件名+suffix

Erlang常見錯誤

Erlang cookie

  • Erlang節點通過交換作為令牌的Erlang cookie以獲得認證。
  • 通常存儲在~/.erlang.cookie

Erlang節點

  • 長節點名name:rabbit@hostname.network.tld
  • 短節點名sname:rabbit@hostname,默認方式

Mnesia數據庫

  • RabbitMQ啟動時會先啟動Mnesia
  • MNESIA_BASE目錄寫權限,Mnesia基于主機名創建數據庫。

Erlang相關操作

  • 啟動節點:erl -sname node_name
  • 列出已連接的節點:node().
  • 查看已運行的節點:net_adm:name().,使用net_adm模塊調用name()函數,此處顯示的RabbitMQ端口并不是AMQP連接的端口。
  • ping檢測其它節點:net_adm:ping('rabbit@hostname').,響應為pong則連接成功,為pang則連接失敗。需共享Erlang cookie。
  • 遠程執行rabbit函數:rpc:call('rabbit@hostname',module_name,function_name,[show_items]),如:rpc:call('rabbit@hostname',erlang,system_info,[process_count])rpc:call('rabbit@hostname',mnesia,info,[])
  • 退出節點:q().

RabbitMQ應用程序設計

從同步編程模型轉向異步編程模型

  • 圖片上傳并行處理
  • 告警通知郵件
  • 實現分布式遠程過程調用

發后既忘處理模型

  • 批處理:將單張圖片上傳并轉換成眾多其它尺寸和格式。
  • 告警通知:不需要擔心發送目標和發送方式。
  • 用戶積分獎勵
  • 代碼展示

實現RPC遠程調用

私有隊列和發送確認

  • 生產者通過消息頭的reply_to字段確定隊列名稱,并監聽隊列等待應答。
  • 消費者能夠檢查reply_to字段,然后創建包含應答內容的新的消息,并以隊列名稱作為路由鍵。
  • 此處可在用于消費的同一條信道上發布應答消息。
  • 使用reply_to作為發布應答消息的目的地;發布時無須指定交換器。
  • 代碼展示
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,967評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,273評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,870評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,527評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,010評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,250評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,769評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,656評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,853評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,103評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,487評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,815評論 2 372

推薦閱讀更多精彩內容

  • 關于消息隊列,從前年開始斷斷續續看了些資料,想寫很久了,但一直沒騰出空,近來分別碰到幾個朋友聊這塊的技術選型,是時...
    預流閱讀 585,195評論 51 786
  • RabbitMQ 原理介紹及安裝部署 標簽:RabbitMQ 安裝 簡介 RabbitMQ 是一個用 Erlang...
    神仙CGod閱讀 8,596評論 0 60
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,781評論 18 139
  • 來源 RabbitMQ是用Erlang實現的一個高并發高可靠AMQP消息隊列服務器。支持消息的持久化、事務、擁塞控...
    jiangmo閱讀 10,374評論 2 34
  • 整體架構 部署步驟 基于 Docker 基本概念內存節點只保存狀態到內存,例外情況是:持久的 queue 的內容將...
    mvictor閱讀 12,769評論 5 30