訊息代理(一),何謂 Message Broker,如何挑選?
過去人們的溝通方式主要是透過口語及書信交流,遠距離的溝通效率低下,而且很容易受到環境的影響。但現代社會中,只要有網路覆蓋的地區,我們的資訊都能透過 TCP/IP 的架構所傳遞,效率相對於過去提高了非常多。
但是在此架構下,我們需要考慮的事情也多了許多。例如要思考傳送訊息時對方是否在線上?不在時該怎麼處理;如果傳送的訊息一下太多,系統負荷不了該怎麼辦?
由於訊息傳遞的速度太快,我們不能依靠人工來決策並處理,而是需要一套完整的邏輯來處理這些瑣事,以下便來整理我學習 System Design 時,關於傳遞訊息時需要考量的重要設計:訊息代理。
什麼是訊息代理 Message Broker?
當我們要寄送郵件給某人,通常需要透過「郵局」這項服務來達成。如果沒有郵局的存在,我們可能需要派另外一個人或是親自將郵件拿到對方手裡,麻煩的事情就來了:萬一對方家中沒有信箱、更甚至是人也不在家呢?
有了郵局的存在,我們便可以將信件交給郵局,再請他們轉交給我們指定的收件者即可。至於如何轉交?郵局可以派人將信件送到對方信箱,就算對方沒有信箱、人也不在家,也能夠多送幾次,或是將信件留在郵局裡,請對方自行來領。
這裡的「郵局」便是我們與對方之間的「訊息代理」,英文稱作 Message Broker。當我們想傳遞訊息時,只要有 Message Broker 的存在,我們就不需要知道對方的物理狀態為何(例如是否在家),也不需要知道訊息怎麼交付到對方手上(例如直接送到家,或是放在郵局請對方來領)。
訊息代理 Message Broker,就是一個負責接收、暫存、發送資訊的服務,解耦寄件者和收件者當中的聯繫。身為寄件者,唯一需要溝通的對象就只有 Message Broker,在提供訊息之後,就沒我們的事了。
為何我們需要 Message Broker?
寄件者和收件者的解耦、實現非同步通訊
在網際網路的世界中,傳遞訊息往往不是只有單一的寄件者和收件者這麼直觀,有可能有多個收件者,甚至是多個寄件者,所以「解耦」寄件者和收件者這件事情相當重要。
例如,我在一個線上聊天室中發言,其他身處同一聊天室的使用者都會同步接收到訊息。如果沒有 Message Broker 的存在,我就需要維護其他使用者的狀態,當用戶 A 不在線上時,我要等著他上線時再重送他沒有收到的訊息。
那如果我下線了,誰要負責把我送出的訊息傳給等等才會上線的用戶 A 呢?Message Broker 的存在就相當必要了。
這個聊天室的例子也告訴我們,透過傳輸接收方的解耦,有些 Message Broker 也能幫助達成「非同步」通訊,不需要雙方同時在線上依舊可以成功的傳輸訊息。
充當訊息的緩衝區,增加傳輸可靠性
除了解耦寄件者和收件者外,在計算機的領域當中還需要考慮訊息的「量」。當傳輸的速率(也就是單位時間內的資料數量、大小)遠大於接收的速率時,就很有可能在接收方會因為無法消化龐大的訊息,而造成訊息遺失甚至是系統崩潰。
這種情況在 IoT(Internet of Thing)的產業中就時常出現,舉個例子來說,一個監測環境資訊的服務會部署相當多的感測器(Sensors),用來測量諸如氣溫、濕度、風速等等指標。而這些感應器的數量、採樣的頻率可能會挺高的,像是放置 1000 個溫度計,每 0.1 秒記錄一筆 1KB 的溫度資料,那麼每秒鐘就會產生 10 MB 的資料,相當於每小時 36 GB。
如果我們有多台伺服器,用來取得不同的資料來做不同的分析,那就很有必要架設一座專門的 Message Broker 來接收感測器的原始資料,並讓各台伺服器能各取所需的擷取想要的資料。
而這座 Message Broker 的目標便是根據不同需求來充當訊息的緩衝區,如果我們不太能承擔資料遺失的風險,那麼 Message Broker 就可以設計成一個 Queue(佇列)的形狀,讓接收方處理完畢再去取得下一筆資料;但若是像溫度這類掉了一兩筆也沒什麼關係的資料,Message Broker 就可以設計成讓接收方永遠只拿最新的一筆,來減緩硬體處理性能的瓶頸。
如此一來,Message Broker 這樣的緩衝區,便能增加訊息傳遞的可靠性。
選擇 Message Broker 的要素
根據想要達成的目的不同,我們需要的 Message Broker 就會有不同的樣貌,但是大致有以下兩點屬性可以考慮:資料量大小、可靠性及持久性。
先說資料量大小,如果要能處理海量資料,例如不斷產生的系統日誌、感測器資料,就可以挑選 Kafka 和 Redis Pub-Sub 這種專門針對高流通量(Throughput)所設計的 Message Broker。
再來是可靠性及持久性,像是金融交易記錄、排程任務這類不太能遺失的資料,便需要選擇如 Kafka 及 RabbitMQ,能夠在 Broker 內將資料儲存一陣子;反之,像是手機跳出的即時推播通知,就不一定要這麼可靠,漏掉一些 App 的廣告也無傷大雅。
因此,根據我們的需求,可以從這兩種屬性來下手挑選 Message Broker:
資料流通量大、可靠及持久性高:如系統日誌、金融交易分析,可使用 Kafka,既能夠處理海量訊息,也不怕掉資料,但是需要的硬體資源和部署複雜度也相對較高
資料流通量大、可靠及持久性低:如大型聊天室的即時訊息(若是不需儲存歷史訊息),可使用 Redis Pub-Sub,在此情境中我們只在乎能否低延遲的傳遞即時訊息,而不在乎偶爾的資料遺失
資料流通量低、可靠及持久性高:如排程任務,一個任務可能要一台 Worker 伺服器處理一段時間後才處理下一個,因此資料量通常不大,但是要做的任務資訊不能夠遺失,則可使用 RabbitMQ
資料流通量低、可靠及持久性低:如臨時的訊息廣播,可考慮用 Redis Pub-Sub,或甚至就不需特別挑選 Message Broker 了,不一定所有涉及訊息傳輸的服務都要使用 Mesage Broker,直接在應用程式中收發資料並處理,反而能減低維護服務的複雜度
如果我們想開發的服務符合這些需求,便可以如上所說的挑選合適的 Message Broker。
不過還是需要留意「殺雞焉用牛刀」,雖然像是 Kafka 這樣的 Message Broker 功能強大,幾乎每種需求都能滿足,但是在部署和維護上也就複雜非常多,是真的非常多。若是沒有強烈的資料量大和可靠程度的考量,我認爲挑選越「簡單」的服務越好。