《喫透 MQ 系列》之扒開 Kafka 的神祕面紗

大家好,我是武哥。這是《喫透 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 的架構設計,我們下期見!

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