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 可以保證分區內部有序而不能保證全局有序。

核心概念

架構圖

image.png

上圖是一個典型的 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 高性能的原因之一。image.png

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 的分區數。image.png

尾聲(嘮叨)

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

下期我會從整體梳理 Kafka 生產者,包括消息發送客戶端,發送端數據快取從源碼角度看看其中的設計模式,程式碼組織技巧。

Tags: