大家好,這是《吃透 MQ 系列》的第二彈,有些珊珊來遲,後臺被好幾個讀者催更了,實屬抱歉!
這篇文章拖更了好幾周,起初的想法是:圍繞每一個具體的訊息中介軟體,不僅要寫透,而且要控制好篇幅,寫下來發現實在太難了,兩者很難兼得。
最後決定還是分成多篇寫吧。一方面,能加快下輸出頻率;另一方面,大家也更容易消化。
廢話不多說了,第二彈開始發車。
01 為什麼從 Kafka 開始?
《吃透 MQ 》的開篇 圍繞 MQ 「一發一存一消費」的本質展開,講解了 MQ 的通用知識,同時系統性地回答了:如何著手設計一個 MQ?
從這篇文章開始,我會講解具體的訊息中介軟體, 之所以選擇從 Kafka 開始,有 3 點考慮:
第一,RocketMQ 和 Kafka 是目前最熱門的兩種訊息中介軟體,網際網路公司應用最為廣泛,將作為本系列的重點。
第二,從 MQ 的發展歷程來看,Kafka 先於 RocketMQ 誕生,並且阿里團隊在實現 RocketMQ 時,充分借鑑了 Kafka 的設計思想。掌握了 Kafka 的設計原理,後面再去理解 RocketMQ 會容易很多。
第三,Kafka 其實是一個輕量級的 MQ,它具備 MQ 最基礎的能力,但是在延遲佇列、重試機制等高階特性上並未做支援,因此降低了實現複雜度。從 Kafka 入手,有利於大家快速掌握 MQ 最核心的東西。
交代完背景,下面請大家跟著我的思路,一起由淺入深地分析下 Kafka。
02 扒開 Kafka 的面紗
在深入分析一門技術之前,不建議上來就去了解架構以及技術細節,而是先弄清楚它是什麼?它是為了解決什麼問題而產生的?
掌握這些背景知識後,有利於我們理解它背後的設計考慮以及設計思想。
在寫這篇文章時,我查閱了很多資料,關於 Kafka 的定義可以說五花八門,不仔細推敲很容易懵圈,我覺得有必要帶大家捋一捋。
我們先看看 Kafka 官網給自己下的定義:
Apache Kafka is an open-source distributed event streaming platform.
翻譯成中文就是:Apache Kafka 是一個開源的分散式流處理平臺。
Kafka 不是一個訊息系統嗎?為什麼被稱為分散式的流處理平臺呢?這兩者是一回事嗎?
一定有讀者會有這樣的疑問,要解釋這個問題,需要先從 Kafka 的誕生背景說起。
Kafka 最開始其實是 Linkedin 內部孵化的專案,在設計之初是被當做「資料管道」,用於處理以下兩種場景:
1、運營活動場景:記錄使用者的瀏覽、搜尋、點選、活躍度等行為。
2、系統運維場景:監控伺服器的 CPU、記憶體、請求耗時等效能指標。
可以看到這兩種資料都屬於日誌範疇,特點是:資料實時生產,而且資料量很大。
Linkedin 最初也嘗試過用 ActiveMQ 來解決資料傳輸問題,但是效能無法滿足要求,然後才決定自研 Kafka。
所以從一開始,Kafka 就是為實時日誌流而生的。瞭解了這個背景,就不難理解 Kafka 與流資料的關係了,以及 Kafka 為什麼在大資料領域有如此廣泛的應用?也是因為它最初就是為解決大資料的管道問題而誕生的。
接著再解釋下:為什麼 Kafka 被官方定義成流處理平臺呢?它不就提供了一個資料通道能力嗎,怎麼還和平臺扯上關係了?
這是因為 Kafka 從 0.8 版本開始,就已經在提供一些和資料處理有關的元件了,比如:
1、Kafka Streams:一個輕量化的流計算庫,性質類似於 Spark、Flink。
2、Kafka Connect:一個資料同步工具,能將 Kafka 中的資料匯入到關聯式資料庫、Hadoop、搜尋引擎中。
可見 Kafka 的野心不僅僅是一個訊息系統,它早就在往「實時流處理平臺」方向發展了。
這時候,再回來看 Kafka 的官網介紹提到的 3 種能力,也不難理解了:
1、資料的釋出和訂閱能力(訊息佇列)
2、資料的分散式儲存能力(儲存系統)
3、資料的實時處理能力(流處理引擎)
這樣,kafka 的發展歷史和定義基本縷清了。當然,這個系列僅僅關注 Kafka 的前兩種能力,因為這兩種能力都和 MQ 強相關。
03 從 Kafka的訊息模型說起
理解了 Kafka 的定位以及它的誕生背景,接著我們分析下 Kafka 的設計思想。
上篇文章中我提到過:要吃透一個MQ,建議從 「訊息模型」 這種最核心的理論層面入手,而不是一上來就去看技術架構,更不要直接進入技術細節。
所謂訊息模型,可以理解成一種邏輯結構,它是技術架構再往上的一層抽象,往往隱含了最核心的設計思想。
下面我們嘗試分析下 Kafka 的訊息模型,看看它究竟是如何演化來的?
首先,為了將一份訊息資料分發給多個消費者,並且每個消費者都能收到全量的訊息,很自然的想到了廣播。
緊接著問題出現了:來一條訊息,就廣播給所有消費者,但並非每個消費者都想要全部的訊息,比如消費者 A 只想要訊息1、2、3,消費者 B 只想要訊息4、5、6,這時候該怎麼辦呢?
這個問題的關鍵點在於:MQ 不理解訊息的語義,它根本無法做到對訊息進行分類投遞。
此時,MQ 想到了一個很聰明的辦法:它將難題直接拋給了生產者,要求生產者在傳送訊息時,對訊息進行邏輯上的分類,因此就演進出了我們熟知的 Topic 以及釋出-訂閱模型。
這樣,消費者只需要訂閱自己感興趣的 Topic,然後從 Topic 中獲取訊息即可。
但是這樣做了之後,仍然存在一個問題:假如 多個消費者都對同一個 Topic 感興趣(如下圖中的消費者 C),那又該如何解決呢?
如果採用傳統的佇列模式(單播),那當一個消費者從佇列中取走訊息後,這條訊息就會被刪除,另外一個消費者就拿不到了。
這個時候,很自然又想到下面的解決方案:
也就是:當 Topic 每增加一個新的消費者,就「複製」一個完全一樣的資料佇列。
這樣問題是解決了,但是隨著下游消費者數量變多,將引發 MQ 效能的快速退化。尤其對於 Kafka 來說,它在誕生之初就是處理大資料場景的,這種複製操作顯然成本太高了。
這時候,就有了 Kafka 最畫龍點睛的一個解法:它將所有訊息進行了持久化儲存,由消費者自己各取所需,想取哪個訊息,想什麼時候取都行,只需要傳遞一個訊息的 offset 即可。
這樣一個根本性改變,徹底將複雜的消費問題又轉嫁給消費者了,這樣使得 Kafka 本身的複雜度大大降低,從而為它的高效能和高擴充套件打下了良好的基礎。(這是 Kafka 不同於 ActiveMQ 和 RabbitMQ 最核心的地方)
最後,簡化一下,就是下面這張圖:
這就是 Kafka 最原始的訊息模型。
這也間接解釋了第二章節中:為什麼官方會將 Kakfa 同時定義成儲存系統的原因。
當然 Kafka 的精妙設計遠非這些,由於篇幅原因,後面的文章再接著分析。
04 寫在最後
這篇文章從 Kafka 的誕生背景講起,帶大家捋清了 Kafka 的定義和它要解決的問題。
另外,一步步分析了 Kafka 的訊息模型和設計思想,這是 Kafka 最頂層的抽象。
希望大家有所收穫,下篇文章將會深入分析 Kafka 的架構設計,我們下期見!
作者簡介:985碩士,前亞馬遜工程師,現58轉轉技術總監
歡迎掃描下方的二維碼,關注我的個人公眾號:武哥漫談IT,精彩原創不斷!