沒想到簡簡單單幾張圖,就能把Kafka講的如此透徹

今天咱們來聊聊 Kafka ,主要是帶你從新認識一下 Kafka,聊一下 Kafka 中比較重要的概念和問題。在後面的文章中我會介紹:git

  1. Kafka 的一些高級特性好比工做流程。
  2. 使用 Docker 安裝 Kafka 並簡單使用其發送和消費消息。
  3. Spring Boot 程序如何使用 Kafka 做爲消息隊列。


咱們如今常常提到 Kafka 的時候就已經默認它是一個很是優秀的消息隊列了,咱們也會常常拿它給 RocketMQ、RabbitMQ 對比。我以爲 Kafka 相比其餘消息隊列主要的優點以下:數據庫

  • 極致的性能 :基於 Scala 和 Java 語言開發,設計中大量使用了批量處理和異步的思想,最高能夠每秒處理千萬級別的消息。
  • 生態系統兼容性無可匹敵 :Kafka 與周邊生態系統的兼容性是最好的沒有之一,尤爲在大數據和流計算領域。


實際上在早期的時候 Kafka 並非一個合格的消息隊列,早期的 Kafka 在消息隊列領域就像是一個衣衫襤褸的孩子同樣,功能不完備而且有一些小問題好比丟失消息、不保證消息可靠性等等。固然,這也和 LinkedIn 最先開發 Kafka 用於處理海量的日誌有很大關係,哈哈哈,人家原本最開始就不是爲了做爲消息隊列滴,誰知道後面誤打誤撞在消息隊列領域佔據了一席之地。

隨着後續的發展,這些短板都被 Kafka 逐步修復完善。因此,Kafka 做爲消息隊列不可靠這個說法已通過時!安全

初識 Kafka

先來看一下官網對其的介紹,應該是最權威和實時的了。是英文也沒有關係,我已經將比較重要的信息都爲你提取出來了。服務器


從官方介紹中咱們能夠獲得如下信息:

Kafka 是一個分佈式流式處理平臺。這究竟是什麼意思呢?

流平臺具備三個關鍵功能:架構

  • 消息隊列:發佈和訂閱消息流,這個功能相似於消息隊列,這也是 Kafka 也被歸類爲消息隊列的緣由。
  • 容錯的持久方式存儲記錄消息流:Kafka 會把消息持久化到磁盤,有效避免了消息丟失的風險·。
  • 流式處理平臺: 在消息發佈的時候進行處理,Kafka 提供了一個完整的流式處理類庫。


Kafka 主要有兩大應用場景:併發

  • 消息隊列 :創建實時流數據管道,以可靠地在系統或應用程序之間獲取數據。
  • 數據處理: 構建實時的流數據處理程序來轉換或處理數據流。


關於 Kafka 幾個很是重要的概念:負載均衡

  • Kafka 將記錄流(流數據)存儲在 topic 中。
  • 每一個記錄由一個鍵、一個值、一個時間戳組成。

 

Kafka 消息模型

題外話:早期的 JMS 和 AMQP 屬於消息服務領域權威組織所作的相關的標準,我在 JavaGuide的 《消息隊列其實很簡單》這篇文章中介紹過。可是,這些標準的進化跟不上消息隊列的演進速度,這些標準實際上已經屬於廢棄狀態。因此,可能存在的狀況是:不一樣的消息隊列都有本身的一套消息模型。異步

隊列模型:早期的消息模型


使用隊列(Queue)做爲消息通訊載體,知足生產者與消費者模式,一條消息只能被一個消費者使用,未被消費的消息在隊列中保留直到被消費或超時。 好比:咱們生產者發送 100 條消息的話,兩個消費者來消費通常狀況下兩個消費者會按照消息發送的順序各自消費一半(也就是你一個我一個的消費。)

隊列模型存在的問題:

假如咱們存在這樣一種狀況:咱們須要將生產者產生的消息分發給多個消費者,而且每一個消費者都能接收到完成的消息內容。

這種狀況,隊列模型就很差解決了。不少比較槓精的人就說:咱們能夠爲每一個消費者建立一個單獨的隊列,讓生產者發送多份。這是一種很是愚蠢的作法,浪費資源不說,還違背了使用消息隊列的目的。分佈式

發佈-訂閱模型:Kafka 消息模型


發佈-訂閱模型主要是爲了解決隊列模型存在的問題。

發佈訂閱模型(Pub-Sub) 使用主題(Topic) 做爲消息通訊載體,相似於廣播模式;發佈者發佈一條消息,該消息經過主題傳遞給全部的訂閱者,在一條消息廣播以後才訂閱的用戶則是收不到該條消息的。

在發佈 - 訂閱模型中,若是隻有一個訂閱者,那它和隊列模型就基本是同樣的了。因此說,發佈 - 訂閱模型在功能層面上是能夠兼容隊列模型的。

Kafka 採用的就是發佈 - 訂閱模型。

RocketMQ 的消息模型和 Kafka 基本是徹底同樣的。惟一的區別是 RocketMQ 中沒有隊列這個概念,與之對應的是 Partition(分區)。ide

Kafka 重要概念解讀

Kafka 將生產者發佈的消息發送到 Topic(主題) 中,須要這些消息的消費者能夠訂閱這些 Topic(主題),以下圖所示:


Kafka Topic Partition

上面這張圖也爲咱們引出了,Kafka 比較重要的幾個概念:

  • Producer(生產者):產生消息的一方。
  • Consumer(消費者):消費消息的一方。
  • Broker(代理):能夠看做是一個獨立的 Kafka 實例。多個 Kafka Broker 組成一個 Kafka Cluster。


同時,你必定也注意到每一個 Broker 中又包含了 Topic 以及 Partition 這兩個重要的概念:

  • Topic(主題):Producer 將消息發送到特定的主題,Consumer 經過訂閱特定的 Topic(主題) 來消費消息。
  • Partition(分區):Partition 屬於 Topic 的一部分。一個 Topic 能夠有多個 Partition ,而且同一 Topic 下的 Partition 能夠分佈在不一樣的 Broker 上,這也就代表一個 Topic 能夠橫跨多個 Broker 。這正如我上面所畫的圖同樣。


劃重點:Kafka 中的 Partition(分區) 實際上能夠對應成爲消息隊列中的隊列。這樣是否是更好理解一點?

另外,還有一點我以爲比較重要的是 Kafka 爲分區(Partition)引入了多副本(Replica)機制。分區(Partition)中的多個副本之間會有一個叫作 leader 的傢伙,其餘副本稱爲 follower。咱們發送的消息會被髮送到 leader 副本,而後 follower 副本才能從 leader 副本中拉取消息進行同步。

生產者和消費者只與 leader 副本交互。你能夠理解爲其餘副本只是 leader 副本的拷貝,它們的存在只是爲了保證消息存儲的安全性。當 leader 副本發生故障時會從 follower 中選舉出一個 leader,可是 follower 中若是有和 leader 同步程度達不到要求的參加不了 leader 的競選。

Kafka 的多分區(Partition)以及多副本(Replica)機制有什麼好處呢?

  1. Kafka 經過給特定 Topic 指定多個 Partition, 而各個 Partition 能夠分佈在不一樣的 Broker 上, 這樣便能提供比較好的併發能力(負載均衡)。
  2. Partition 能夠指定對應的 Replica 數, 這也極大地提升了消息存儲的安全性, 提升了容災能力,不過也相應的增長了所須要的存儲空間。

 

ZooKeeper 在 Kafka 中的做用

要想搞懂 ZooKeeper 在 Kafka 中的做用 必定要本身搭建一個 Kafka 環境而後本身進 ZooKeeper 去看一下有哪些文件夾和 Kafka 有關,每一個節點又保存了什麼信息。 必定不要光看不實踐,這樣學來的也終會忘記!

後面的文章中會介紹如何搭建 Kafka 環境,你且不要急,看了後續文章 3 分鐘就能搭建一個 Kafka 環境。

這部份內容參考和借鑑了這篇文章:https://www.jianshu.com/p/a036405f989c 

下圖就是個人本地 Zookeeper ,它成功和我本地的 Kafka 關聯上(如下文件夾結構藉助 idea 插件 ZooKeeper tool 實現)。


ZooKeeper 主要爲 Kafka 提供元數據的管理的功能。

從圖中咱們能夠看出,Zookeeper 主要爲 Kafka 作了下面這些事情:

  • Broker 註冊 :在 Zookeeper 上會有一個專門用來進行 Broker 服務器列表記錄的節點。每一個 Broker 在啓動時,都會到 Zookeeper 上進行註冊,即到/brokers/ids 下建立屬於本身的節點。每一個 Broker 就會將本身的 IP 地址和端口等信息記錄到該節點中去
  • Topic 註冊 :在 Kafka 中,同一個Topic 的消息會被分紅多個分區並將其分佈在多個 Broker 上,這些分區信息及與 Broker 的對應關係也都是由 Zookeeper 在維護。好比我建立了一個名字爲 my-topic 的主題而且它有兩個分區,對應到 zookeeper 中會建立這些文件夾:/brokers/topics/my-topic/partitions/0、/brokers/topics/my-topic/partitions/1
  • 負載均衡 :上面也說過了 Kafka 經過給特定 Topic 指定多個 Partition, 而各個 Partition 能夠分佈在不一樣的 Broker 上, 這樣便能提供比較好的併發能力。對於同一個 Topic 的不一樣 Partition,Kafka 會盡力將這些 Partition 分佈到不一樣的 Broker 服務器上。當生產者產生消息後也會盡可能投遞到不一樣 Broker 的 Partition 裏面。當 Consumer 消費的時候,Zookeeper 能夠根據當前的 Partition 數量以及 Consumer 數量來實現動態負載均衡。
  • ......

 

Kafka 如何保證消息的消費順序?

咱們在使用消息隊列的過程當中常常有業務場景須要嚴格保證消息的消費順序,好比咱們同時發了 2 個消息,這 2 個消息對應的操做分別對應的數據庫操做是:更改用戶會員等級、根據會員等級計算訂單價格。假如這兩條消息的消費順序不同形成的最終結果就會大相徑庭。

咱們知道 Kafka 中 Partition(分區)是真正保存消息的地方,咱們發送的消息都被放在了這裏。而咱們的 Partition(分區)又存在於 Topic(主題)這個概念中,而且咱們能夠給特定 Topic 指定多個 Partition。


Kafka Topic Partitions Layout

每次添加消息到 Partition(分區)的時候都會採用尾加法,如上圖所示。Kafka 只能爲咱們保證 Partition(分區)中的消息有序,而不能保證 Topic(主題)中的 Partition(分區)的有序。

消息在被追加到 Partition(分區)的時候都會分配一個特定的偏移量(offset)。Kafka 經過偏移量(offset)來保證消息在分區內的順序性。

因此,咱們就有一種很簡單的保證消息消費順序的方法:1 個 Topic 只對應一個 Partition。這樣固然能夠解決問題,可是破壞了 Kafka 的設計初衷。

Kafka 中發送 1 條消息的時候,能夠指定 Topic,Partition,Key,Data(數據) 4 個參數。若是你發送消息的時候指定了 Partition 的話,全部消息都會被髮送到指定的 Partition。而且,同一個 key 的消息能夠保證只發送到同一個 partition,這個咱們能夠採用表/對象的 id 來做爲 key 。

總結一下,對於如何保證 Kafka 中消息消費的順序,有了下面兩種方法:

  1. 1 個 Topic 只對應一個 Partition。
  2. (推薦)發送消息的時候指定 Key/Partition。


固然不只僅只有上面兩種方法,上面兩種方法是我以爲比較好理解的,


最後給你們一套Kafka的學習資料。內容從最基礎的架構直接講到高級源碼

目錄

詳細展現

消費者

深刻服務端

高級應用

Kafka與Spark的集成

相應的文章已經整理造成文檔,git掃碼獲取資料看這裏