RabbitMQ 基本介紹 === MQ 為 Message Queue 的簡寫,中文稱消息隊列,而什麼情況下會使用到消息隊列?消息隊列又有什麼作用?下面都會一一解釋。 首先什麼情況會使用到消息隊列,大方向可以想象一個搶票系統,時間到點的時候,會同時有非常大量的請求發送到我們的伺服器中,通常伺服器的硬體效能沒有辦法應付瞬時流量如此大的請求,因此我們會希望這些消息可以“排隊”一下,讓伺服器不要一次處理大量的請求,而是將請求先放在 Message Queue 中再慢慢消耗,同時這麼做也能提升使用者回應的效率,因為只需要將消息塞入 Message Queue 中就可以返回結果了,不需要等到伺服器處理完才回應。 當然前面說到的“票”是有限制數量的,因此可以配合 Redis 進行限流操作,利用 Redis 中的原子操作可以確保請求數量一定是票的數量,Redis 的詳細介紹可以看這篇文章 [Redis 如何應對高流量及高可用實現](https://hackmd.io/@yydrBackend/Hk6ztcsPC)。 Message Queue 四大功能 --- 有了上面的簡易理解後,現在可以說說 Message Queue 能實現的四大主要功用: 1. 削峰填谷 2. 應用解耦 3. 異步提速 4. 消息分發 我喜歡用四個字表達,這樣看起來比較簡潔:100: ### 削峰填谷 先看一下下面的流量時間圖: ![超高山峰](https://hackmd.io/_uploads/By_vWByn0.png) 這張圖表現了在某個瞬時中流量特別大,如果沒有使用 Message Queue 時,很可能在流量大的瞬間伺服器就會崩潰,但如果我們將請求都先放入 Message Queue 中,並且以伺服器可以承受的流量來處理請求,我們可以看到圖片就會變成下圖: ![削峰填谷](https://hackmd.io/_uploads/ryuPMSJnR.png) 這樣就能使得請求可以被處理,伺服器也不會因為突然有大量的請求而崩潰,這就是所謂的“**削峰填谷**”。 ### 應用解耦 現在可以想象 Message Queue 就是一個信箱,我們拿寄信來比喻網路請求。現在用掛號信來舉例沒有使用 Message Queue 的情況,郵差如果要寄掛號信到你手中該怎麼做?他可能會在你家樓下喊你的名字,然後必須要等你下樓拿到信,郵差才能離開。那如果是平信呢?郵差只需要將信投入信箱就可以離開,而你只需要在你有空的時候打開信箱慢慢看裡面有什麼信件就好了。 那麼回到網路請求中,郵差就是使用者,而你就是伺服器,使用 Message Queue 不但可以提升使用者的體驗(因為放進信箱就可以走了),也讓伺服器可以有空時再處理請求;沒有使用 Message Queue 使用者就必須要等到伺服器回應才能繼續其他操作。 而所謂的應用解耦就是,假設後端有四個服務分別在不同的伺服器上,如訂單服務、物流服務、金流服務、賣家服務。假設現在物流服務當機或者正在處理其他請求,那麼使用 Message Queue 的好處就是其他服務可以先處理請求,不必等到物流服務也確實可用才能給出回應,如此也提高系統的可用性,因為如果有任何服務出問題整體系統仍然可以使用(但工程師要很累的加班修 bug 就是了😢)。 ### 異步提速 如果有使用過 Youtube 上傳影片的人,應該有發現影片還沒有完全上傳完,就可以先填寫影片相關的資料如影片標題、影片介紹等資訊,而在使用者填寫資料的同時,影片也可以持續上傳,上傳完成也會自動做影片的內容檢查,這樣的使用體驗就是 Message Queue 的功勞,如果沒有它在,那麼使用者就必須要等到影片上傳完成才可以填寫影片的相關資訊,那麼這就會讓使用者必須等很久才能執行下一步操作,非常影響體驗。 ### 消息分發 現代網頁架構中 Microservices 非常流行,每個服務需要處理的請求也不同,一個 api 的資料可能需要送到很多服務中,每個服務需要的資料又有所不同,因此可以藉助 Message Queue 的功能,將資料分到各個 Queue 中,有訂閱這個 Queue 的服務就可以從中取得資料,以此來將消息分發給需要的服務。 RabbitMQ 中的四種角色 --- 在 RabbitMQ 中一共有四種角色: 1. Producer 2. Exchange 3. Queue 4. Consumer Producer 為生產者,就是負責提供資料的角色,將資料交給 RabbitMQ 處理的伺服器。 Exchange 中文為交換機,在 RabbitMQ 的某些模式會使用,主要負責將拿到的消息分送到各個指定的 Queue 中。 Queue 為佇列,相信有資訊背景的人都對這個詞並不陌生,採取 first in first out 的策略,簡單講就是排隊的地方,被交換機分發的資料會進入 Queue 中排隊。 Consumer 為消費者,負責處理 Queue 中資料的伺服器,當然也不是每個 Queue 中的資料都處理, Consumer 只會根據自己指定的那些 Queue 中處理它們的資料。 RabbitMQ 的六種模式 --- RabbitMQ 共有六種不同的模式,必須根據自己的需求以及業務場景使用不同的模式: 1. Direct 2. Worker 3. Publish / Subscribe 4. Router 5. Topic 6. RPC ### Direct 模式 Direct 模式,或者有人稱為簡單模式,裡面只有三個角色,一個生產者,一個佇列,一個消費者。利用這個模式單純是希望使用削峰填谷的功能,例如伺服器還是傳統的單體架構,但需要 Message Queue 的緩衝時就可以使用此模式,圖示如下: ![Direct mode](https://hackmd.io/_uploads/HyNBfdg30.png) ### Worker 模式 工作模式和簡單模式非常相似,不一樣的地方在於消費者可以不止一個,讓大家可以一起處理這個 Queue 裡面的消息,圖示如下: ![Worker mode](https://hackmd.io/_uploads/B1iEQOlhR.png) ### Publish / Subscribe 模式 發佈/訂閱模式,也有人簡寫為 Pub/Sub,這個概念不止在 RabbitMQ 上使用,有興趣可以搜尋 Publish/Subscribe。這個概念可以很直觀的想到 Youtube 的訂閱,當你訂閱一個創作者,那麼這個創作者發新影片的同時你就會收到通知。 在 RabbitMQ 中也是同理的,消息發佈者不會將消息直接發送給特定的訂閱者,而是將消息發送到交換機上,而交換機的工作就是將消息發送到所有綁定在這個交換機的佇列上,而訂閱者只要監聽自己負責的佇列即可,圖示如下: ![Pub/Sub mode](https://hackmd.io/_uploads/B1JzLdg3A.png) ### Router 模式 可以注意到剛才的 Publish/Subscribe 模式,交換機把所有送來的消息發送到所有綁定在這個交換機上的佇列,但如果有的消息我不想讓所有的佇列都收到呢?此時就需要使用 Router 模式,現在生產者不能在將資料直接發給交換機就好,還需要附帶一個 router key 讓交換機知道這個消息要送給誰,圖示如下: ![Router mode](https://hackmd.io/_uploads/ryKhXtgnR.png) ### Topic 模式 Topic 模式基本上是 Router 模式的擴充版本,他支援 router key 的模糊匹配,就像關鍵字搜尋一樣,但實務上仍然建議使用 Router 模式,使用 Topic 模式會造成一定的性能衰減。 在模糊匹配中有兩個符號可以使用: 1. #:代表可以匹配一個或多個關鍵詞 2. *:代表可以匹配一個關鍵詞 圖示如下: ![Topic mode](https://hackmd.io/_uploads/HJuj8FgnR.png) ### RPC 模式 這個模式基本上不會使用,但因為有所以還是寫一下。從上面可以發現當生產者發送消息出去之後,並不會知道這個消息被消費成功、失敗、或是根本沒有被消費,如果今天的業務需求要知道是否成功或失敗,並且在後續需要繼續處理,那麼就需要使用 RPC 模式。RPC 模式本身是一個線程阻塞的狀態,非常影響性能,圖示如下: ![RPC mode](https://hackmd.io/_uploads/ryDrcYl2A.png) Exchange 交換機的一些概念 --- 從上面可以發現,交換機被應用在 Publish/Subscribe、Router、Topic 模式中,也因此交換機出現對應的三種類型: 1. **Fanout**:廣播類型,也就是應用在 Publish/Subscribe 模式的交換機,他將收到的消息發送給每一個綁定在自己身上的佇列 2. **Direct**:定向類型,也就是應用在 Router 模式的交換機,他將消息發送到匹配的 router key 上 3. **Topic**:通配類型,也就是應用在 Topic 模式的交換機,他將消息發送到符合 routing pattern 的佇列中 另外別忘記,交換機只負責轉送資料,不負責任何資料的儲存,因此如果沒有任何 Queue 綁定在這個交換機上,或者沒有匹配到任何的 router key,那麼這筆資料就會直接流失