1. 程式人生 > 實用技巧 >Kafka 探險 - 架構簡介

Kafka 探險 - 架構簡介

Kafka 探險 - 架構簡介

這個 Kafka 的專題,我會從系統整體架構,設計到程式碼落地。和大家一起槓原始碼,學技巧,漲知識。希望大家持續關注一起見證成長!
我相信:技術的道路,十年如一日!十年磨一劍!

簡介

Kafka 是一種分散式的,基於釋出 / 訂閱的訊息系統。最初被 LinkedIn 開發,並在 2011 年初開源,2012 年 10 月從 Apache 孵化器破殼而出,成為 Apache 的頂級專案。

Kafka 最初被設計的目的是 LinkedIn 流量和運維資料分析。流量資料包含 PV (Page View) , UV (Unique Visitor) ,搜尋資料,詳情頁資料等。在高併發場景對於這些資料的統計並非實時的,不是簡單的對於資料庫的某個欄位資料量 +1 這麼簡單,超大的流量洪峰下並不能因為統計資料將業務主流程阻塞。所以通常會將這些資料記錄在檔案或大資料儲存引擎中,然後週期性的進行統計分析。

Kafka 被越來越多的公司青睞主要和他的特性優勢有關:

  • 以 O(1) 時間複雜度訊息持久化,對於 TB 級別的資料也能夠保證 O(1) 的訪問效率
  • 支援批量 資料,並且對於資料進行壓縮保證高吞吐
  • 支援訊息分割槽,分散式傳送,分散式消費,便於水平擴充套件 (Scale out),具有很高的併發能力

應用場景

那為何需要使用訊息佇列,或者說在什麼場景下 Kafka 更加合適

解耦

在大資料,高併發的場景下為了突破效能瓶頸會對系統進行水平擴充套件和垂直拆分,將一個複雜的系統拆分多個獨立,純淨的子系統。資料在各個系統之間流轉,但是如果某一個服務處理速度過慢,就會拖累整個鏈路的效能,形成瓶頸降低整個系統的效能,造成“旱的旱死澇的澇死”的局面。

舉個簡單例子:在淘寶下單時,交易系統完成扣款,後續會有很多動作:提醒賣家發貨,生成賣家工作流,核銷優惠券,增加購物積分等等,如果這一步全部寫到交易系統的扣款程式碼之後,很有可能交易系統就會被拖死,下游任何一個環節失敗也會導致扣款回滾,並且如果需要新增一個新的動作需要交易去做大量修改,設計肯定是不合理的。實際上交易系統在處理完扣款後會傳送一個扣款完成訊息,下游接這個訊息即可,下游失敗不會影響核心流程失敗,並且各個系統的邊界更加清楚,分層更更加合理。

資料持久化

如今的應用程式基本都會涉及到多個系統之間的對接,資料在系統之間通過 RPC 進行傳遞,處理資料的過程失敗就會導致資料丟失,除非資料被持久化到磁碟上。而 Kafka 將所有需要流轉的資料都 持久化到磁碟上

,保證資料不會丟失。另外還有一個很重要的能力就是保留現場便於後續問題排查跟蹤,經歷過系統失敗但是無法復現的人才會體會到的痛!

為了保證磁碟上的資料不會爆炸式瘋漲,Kafka 提供了資料清理,資料壓縮等功能,清除處理完成的歷史資料。

擴充套件性

在應用的訪問量劇增的情況下,程式碼優化往往沒有直接進行水平擴充套件來的那麼及時。診斷,分析,方案,優化,驗證 一系列複雜流程讓程式碼優化看起來只能是一個從長計議的方案。這時止血的方案只能是降級,限流,擴機器 三板斧。Kafka 的擴充套件性主要就體現在能熱擴容,不需要修改引數,不需要修改程式碼,上機器 -> 註冊服務 就完成了擴容。並非所有系統都具備這個像 調節音量旋鈕一樣簡單的提高系統性能的能力,這裡會涉及到擴容之前的資料是否會有熱點,新節點對叢集的同步,流量重分配等等一系列複雜流程。

容災

系統的部分元件失敗不會影響這個系統的執行,訊息佇列降低了程序間的耦合度,上游或者下游服務掛掉後不會影響其他系統的執行,在服務重新線上後能夠繼續處理之前未處理的資料,只是會存在一定的延時但是能夠保證 最終業務正確性

保序

強哥:你這瓜保熟嗎?哦不,你這佇列保序嗎?
在大多數場景下,資料處理順序是至關重要的,順序錯亂很可能導致資料結果錯誤。除非這個處理過程是無狀態的,此時訊息只是起到事件觸發的作用,觸發下游進行計算。Kafka 可以保證分割槽內部有序而不能保證全域性有序。

核心概念

架構圖

上圖是一個典型的 Kafka 架構圖,左邊為訊息生產者(Producer) ,傳送訊息到一個特定的主題(Topic),由於 Kafka 的分散式設計每個 Topic 被分成多個分割槽,因此傳送到每個 Topic 的訊息會被儲存到對應的分割槽。另外如果 Topic 設定了副本,則每個分割槽都會有對應的副本。這些 Topic 被不同的消費者(Consumer)訂閱,如果兩個消費者在同一個消費者組,那麼裡面的消費者只能訂閱一個固定的分割槽。

用上圖的 Topic A 舉例, Producer 1 傳送訊息到 Topic-A ,訊息會在存放在 Broker-2 和 Broker-3 的兩個分割槽上,並且由於 Topic-A 開啟了分割槽備份,所以每個分割槽都會由另外一個節點 Topic-A' 備份分割槽資料 。傳送到 Broker 的資料會被消費者訂閱,由於 Consumer-1 和 Consumer-2 在同一個消費者組中,他們只能消費一個固定分割槽的訊息, Consumer-1 只會接收到 Topic-A Partition-1 的訊息,Consumer-2 只會接收到 Topic-A Partition-0 的訊息。

Broker

在 Kafka 叢集中的一個 Kafka Server 就是一個 Broker ,生產者將訊息投遞到 Broker ,Broker 保證訊息的 持久化,容災,準確性等。同時接受消費者的訊息訂閱,向消費者分發訊息。一般來說在生產環境一臺 Kafka 伺服器就是一個 Broker。

Topic & Partition & Log

Topic 可以認為是用來儲存訊息的邏輯概念,可簡單認為他是一個 信箱。每條訊息傳送的時候都需要指定需要傳送到哪個 Topic ,訊息被消費的時候也需要指定消費哪個 Topic 中的訊息。

Kafka 為了提高可擴充套件性以及吞吐量,Topic 被分成多個分割槽 (Partition) ,每個 Partition 對應一個 Log,Log 是一個邏輯概念, 它會對應伺服器上一個資料夾,這個資料夾下存放的是這個 Partition 下所有的訊息資料和訊息索引。在面對海量資料的時候,為了避免出現巨大檔案出現 I/O 瓶頸,Kafka 又將 Log 分為多個 Segment 。每個 Segment 包含 log 檔案index 檔案檔案命名是以該 Segment 第一條訊息的 offset 命名。這樣說下來其實還是很繞的直接看下面的架構圖,可以仔細留意一下各個部分的標識和數字再結合這段文字,理解起來應該就很輕鬆了。

另外因為 Kafka 採用順序 I/O,順序 I/O 效率非常高,甚至比隨機寫記憶體效率更高,這也是 Kafka 高效能的原因之一。

Replication

在生產環境中,我們一般會開啟 Kafka 訊息冗餘特性,每個 Partition 都有 1 個或多個副本,我們稱之為 Replication。當分割槽只有一個副本的時候,該分割槽資料只保留了一份。每個分割槽副本都會選出一個 Leader , Leader 是所有讀寫請求的 “介面人” ,其餘副本均為 Follower 。Follower 作用有兩個:拉取 Leader 的 Log 資料做 備份,在 Leader 失敗後作為候選人 參與 Leader 選舉

Producer

訊息產出的源頭,通過一定的策略推送到 Topic 的各個分割槽 。這裡所說的推送策略就是訊息路由機制,Kafka 內建多種策略可選例如:按照訊息 Key ,輪訓等等,甚至使用者可以寫擴充套件程式碼來自定義路由策略。

Consumer & Consumer Group

消費者(Consumer)主要工作是從 Broker 拉取訊息,進行消費處理。每個消費者維護自己的消費進度,這樣的設計有諸多好處,比如:每個消費者進度能夠輕鬆的進行區分,並且可以修改單個消費者的消費位點跳過或者重新消費某些訊息,避免了位點資訊的集中化管理的單點故障問題。

現在的應用程式大部分為分散式的系統,一個應用有幾十臺上百臺伺服器,這些伺服器上執行著相同的程式碼,那麼一個訊息過來,每臺伺服器都執行一次消費邏輯,豈不是會造成巨大的問題。

所以 Kafka 引入了一個新的概念: 消費者組(Consumer Group)。我們可以將這些應用的伺服器都放到同一個消費者組中,而 Kafka 規定一條訊息只能被同一個消費者組中的一個消費者消費,這樣就能完美避免分散式情況下的重複消費問題了。上面所說的情況簡單來說是希望實現訊息被某臺伺服器獨佔,也就是 單播問題。假如我們希望這條訊息被廣播出去,每臺收到這個訊息的伺服器都做處理,例如發訊息做日誌清理,這種情況稱為 廣播, 那我們只需要將每個消費者放到不同的消費者組即可。

Kafka 引入消費者組的概念巧妙解決了單播和廣播問題,而沒有區分訂閱型別,通過一種邏輯概念來遮蔽掉多種訂閱實現。

另外在同一個消費者組中的消費者訂閱的分割槽是確定的,只有在消費者組中的消費者有變化的時候才會進行重分配。例如我們有四個分割槽,三個消費者,就會出現一個消費者訂閱兩個分割槽的情況。而三個分割槽四個消費者就會出現有消費者處於空閒狀態,造成浪費,所以一般消費者的數量儘量不要大於 Topic 的分割槽數。

尾聲(嘮叨)

這是我 2021 年的第一篇部落格,年底做回顧的時候才知道去年我過的究竟有多麼糟糕。既沒有輸入也沒有輸出,雖然工作進入一個新的階段,會越來越忙,但忙不是拒絕成長的藉口,必須保證每月一到兩本書的輸入,一到兩週輸出一篇優質文章。 最長的路屬於一顆孤獨的心,與君共勉

下期我會從整體梳理 Kafka 生產者,包括訊息傳送客戶端,傳送端資料快取從原始碼角度看看其中的設計模式,程式碼組織技巧。