漫談 MQ:要消息隊列(MQ)有什麼用?

大家好,我是煎魚。

最近我有一個朋友公司踩了不少消息隊列(MQ)的坑,讓人無奈不已。因此計劃寫 MQ 系列的技術文章,來科普更多這塊的知識。

目前 MQ 也是互聯網應用中非常常用的基礎組件了,面試特愛問。基本有一定規模的系統都能看見他的蹤影。

無論是 RocketMQ、Kafka、RabbitMQ 等,都圍繞着根本的設計出發產生不同的高級功能,甚至可能是雷同的設計有 N 個名字。

什麼是 MQ

MQ 一般代指消息隊列(Message Queue)。它是一個抽象層,允許多個進程(可能在不同的機器上)通過各種模式(例如:點對點,發佈訂閱等)進行通信。

也可以根據不同的實現,它可以被配置爲保證可靠性、錯誤報告、安全、發現、性能等。

爲什麼需要 MQ

在當下 MQ 的必要場景,比較經典的說辭就是 “異步、削峯、解耦”。是各類秒殺系統的設計核心,甚至會作爲不少雲廠商的賣點,每家都有自己的生態圈。

核心分爲三個要點:

解耦

在業務系統設計中,我們常常會與一個平臺系統 A,他匯聚了許許多多的系統的對接。例如,系統 A 作爲平臺擁有大量用戶操作,自然就有非常多的用戶行爲。

雖然他自己可能不大需要,但是其他子系統就不同了,會要系統 A 來調用他們提供的接口,傳輸各種行爲數據。

其鏈路依賴如下圖:

多重依賴

這時候作爲平臺方的系統 A 就煩死了,來一個要對接一個,就得安排一個人排工期和迭代。對方還有可能出現系統不穩定,還得關注他們的穩定性和訴求。

但用了 MQ 後就不一樣了,如下圖:

MQ 解耦直接依賴

系統 A 只需要將消息放到 MQ 中去,不管以後是對接系統 B、C、D、E...,他都不需要太關心,不用一個個對接。用業務同學的話來講,就是:“自己看文檔,去 MQ 裏拿,別來騷擾我”。

以此 MQ 達到了系統間解耦的目的。

削峯

在 2C 類別的業務系統中,常常會有活動的概念,要面向用戶做促銷,像我們常見的雙 11、618 都是這類營銷,也是營銷場景。

但這種場景之下,會對系統產生較大的衝擊。類似八二原則,也就是 80% 的流量集中在某個時間衝擊進來,形成了流量尖峯(高 QPS),系統會因爲承受不了如此大的壓力,從而宕機。

如下圖:

用戶直接併發訪問

用戶的請求會經由系統 A 直擊數據庫。當然,在活動場景下的大流量,數據庫自然也就撐不住了。

我們可以利用 MQ 做削峯,系統 A 直接把消息寫入 MQ,再讓系統 B、C、D 自己主動地根據自身情況來 MQ 拉取消息,又或是接受消息的推送:

利用 MQ 削峯

這樣一來,MQ 作爲一個 “轉發器”,流量不會直接打到底層,也保證了各業務系統可根據自己的實際負載來決定消費消息的速度,起到流量削峯放緩的作用。

異步

在沒有引入 MQ 組件的時候,我們系統 A 因業務需求要調好幾個接口時,都可能需要專門的寫個異步操作,否則就會導致阻塞等待響應過久。

但是使用 MQ 後,系統只需要快速地將消息寫入 MQ 中,接着就可以返回了:

MQ 異步操作

也就是真正的業務操作,被異步化了。“內部” 的區域是業務系統自身需要關注的,而經由 MQ 的 “外部” 操作與系統 A 無關,自然異步處理也問題不大。

MQ 三要素

MQ 一共有三個基本角色,分別是:

這麼一看,MQ 就是一個很基礎的東西,基本就是一發一存一消費的模型:

MQ 三要素

  1. 在 MQ 中傳來傳去的內容:就是 “消息”,消息是我們業務要傳輸的數據內容。內容格式爲自定義,只要兩邊商議清楚能解析出來即可。比較常見是像是:JSON、Protobuf 等。

  2. 消息在 MQ 的隊列組件:承載着傳輸消息的作用,隊列是先進先出的數據結構,生產者的消息入隊就是發消息,消費者消費消息,也就是隊列出隊。

消息模型

隨着消息的不斷規模使用和應用,目前業內常見的有兩種模型:

點對點模型

點對點是 MQ 最初的結構,也就是 “生產者 - 隊列 - 消費者” 的模型:

點對點模型

生產者將消息寫入隊列,消費者再從隊列中讀取出消息出來,完成一個標準動作。

當然,在真實環境中,是允許有多個生產者和多個消費者的,也可以根據不同的業務訴求做隊列的隔離。

發佈 / 訂閱模型

發佈 / 訂閱是 MQ 逐漸延伸出來的訴求,因爲在實際業務場景中,我們需要將一份消息分發給多個消費者。

多個消費者都要針對這份數據做一些自己的業務處理,那麼點對點的就不合適了,除非點對點的開通 N 個隊列,但消息的體量可也不少,也不高效,這顯然很浪費。

從業務場景來講,就像平時系統 A 有一份用戶行爲數據,下游有 N 個系統需要,那咋辦。最適合的就是 “發佈者 - Topic - 訂閱者” 的模型:

發佈 / 訂閱模型

在該模型中,“生產者” 變成 “發佈者”,“消費者” 變成了 “訂閱者”,以往的 “隊列” 也改變了他單一的屬性,拆成了更多的組件。一般就是 “主題” 了,也就是 Topic 來做消息存儲等。

訂閱者只需要訂閱 Topic,就可以收到發佈者每次發佈的這個 Topic 的全量消息,以此達到訴求。

總結

在今天這篇文章中,我們介紹了消息隊列(MQ)的相關核心內容:

MQ 總是有利有弊的,在初步瞭解後,接下來的文章我們將會持續剖析,歡迎關注煎魚,繼續學習 :)

參考

公衆號

關注煎魚,吸取他的知識 👆

你好,我是煎魚。高一折騰過前端,參加過國賽拿了獎,大學搞過 PHP。現在整 Go,在公司負責微服務架構等相關工作推進和研發。

從大學開始靠自己賺生活費和學費,到出版 Go 暢銷書《Go 語言編程之旅》,再到獲得 GOP(Go 領域最有觀點專家)榮譽,點擊藍字查看我的出書之路

日常分享高質量文章,輸出 Go 面試、工作經驗、架構設計,加微信拉讀者交流羣,記得點贊!

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/UrAJrUBKHNG7-UAabsqLZA