什麼是 RabbitMQ ?
RabbitMQ 是一個 message broker,用來實現服務解耦。解耦聽起來很抽象,簡單來說,就是透過拆解程式碼的運作,避免服務的耦合性過高。
使用情境
舉例情境:目前運行中的專案為購物網站,想新增一個功能,當客戶訂單成立後發 email 到客戶信箱做確認留底。
從上述的情境中,運作流程會類似這樣
從流程看來,購物網站的商業邏輯和發送通知的程式碼會是綁在一起的,然而發送通知實際上能夠抽離出來,獨立作為一項服務,專門發送通知的服務。
此時服務解耦後會像這樣
購物網站
透過 RabbitMQ 傳遞訊息,告訴通知服務
該發信給客戶囉,客戶剛結完帳了。然而這樣做的好處是什麼?
為何需要 RabbitMQ?
服務解耦(service decoupled)的用意在於避免原本的專案因為參雜過多的功能,使得一小部份的 bug 就讓整個服務中斷。
以上方的情境來說,如果發送通知是包含在購物網站
中,此時這部份的程式碼出了問題,整個專案受到影響,無法結帳,公司業務會停擺,但如果發送通知是抽離出來,獨立作為一項服務的話,此時即便通知的程式碼出問題,公司業務能夠持續運作。
概念圖
名詞解釋
要了解 RabbitMQ,認識專有名詞和定義有很大的幫助,以下為使用 Message Queue 時的常見名詞,可以搭配概念圖一起看。
名稱 | 解釋 |
---|---|
message | RabbitMQ 裡所傳遞的物件 |
queue | message 所放置的地方 |
producer | 生成 message 並傳入 queue 裡的角色 |
consumer | 從 queue 中提取 message,並執行內容的角色 |
exchange | 決定 message 要傳入哪個 queue |
routing key | 在 message 身上挾帶的資訊,類似地址,告訴 exchange 這個 message 要被傳入哪個 queue 中 |
binding | 表示 exchange 和 queue 之間的關係 |
channel | 一個 connection 中能包含多個 channel,可以把 channel 想成虛擬的 connection 或 子 connection |
connection | 連結 app 和 RabbitMQ,這邊介紹的是 AMQP 0-9-1 ptotocol |
vhost | 想成一個 container,vhost 裡頭底下包含了 exchange 和 queue |
AMQP 0-9-1 Model 介紹
AMQP (Advanced Message Queuing Protocol),用於 Broker 和其他機器之間的傳輸協議,從上方的概念圖看到,RabbitMQ 扮演著 broker 的角色,介於 Producer 和 Consumer 之間,而 Producer, Broker, Consumer 分別是三台不同的機器,AMQP 就是用於扮演他們之間溝通的協議。
Exchange 類型介紹 (Direct, Fanout, Topic)
在 RabbitMQ 中,Message 從 Producer 傳到了 Exchange 後,如何分配給 Queue,取決於 Exchange 的類型和 binding,這邊介紹三種 Exchage 類型
序號 | 名稱 |
---|---|
1 | Direct |
2 | Fanout |
3 | Topic |
Direct
Direct 為預設的 Exchange 類型,如同名字所寫,Direct Exchange 就直接透過 message 上的 routing_key
以及 binding 的 routing_key
找到對應的 Queue,概念如下圖,圖中的 message 會被送到 Queue 3
中。
Fanout
Fanout 個概念類似廣播,廣播一發送,只要在收聽該電台的人都聽得到,Fanout 在設計上忽略 routing_key
,只要 Exchange 收到 message,會將同樣的 message 發送給所有 binding 的 Queues.
Topic
Topic 相對上面兩種類型稍微複雜一些,Exchange 會發送 Message 給多個 Queue,舉例來說,當客戶退貨的時候,可能需要做發送通知信以及商品數量增加兩件事,而這兩件事可能分送給不同的 Queue 去做處理。
在 Topic Exchange 中, message 的 routing_key
是有特定規範的,會是一段文字,中間由 .
區隔,例如 product.phone.new
,不限制使用多少字,只要小於 255 bytes。
在 rounting_key
中會出現 #
和 *
,用於表達一個 pattern。#
代表沒有任何或是多個單字,*
代表一個單字。(當 rounting_key
中沒有使用到 *
或是 #
,其實跟 Direct Exchange 會是一樣的。)
舉例
routing_key | qualified |
---|---|
*.*.apple |
shop.food.apple , order .item .apple |
trade.# |
trade , trade.car , trade.car.cancelled |
以下方的示意圖來看,message 所夾帶的 routing_key
為 trade.phone.cancelled
,從各個 binding 的 routing_key
確認後,會傳送到 Queue 1
和 Queue 3
。
後記
接觸到 Message Queue 才發現裡面的學問很大,RabbitMQ 可以應用在很多場景,這篇有基礎的概念介紹和名詞解釋,之後要再花時間鑽研鑽研實際應用的部份。
參考資料
https://www.rabbitmq.com/getstarted.html
https://www.cloudamqp.com/blog/part1-rabbitmq-for-beginners-what-is-rabbitmq.html