Apache kafka 工作原理介紹

Apache 程序員 JSON Linkedin 通信 架構師的修煉之路 2018-12-17
Apache kafka 工作原理介紹

消息隊列

消息隊列技術是分佈式應用間交換信息的一種技術。消息隊列可駐留在內存或磁盤上, 隊列存儲消息直到它們被應用程序讀走。通過消息隊列,應用程序可獨立地執行--它們不需要知道彼此的位置、或在繼續執行前不需要等待接收程序接收此消息。在分佈式計算環境中,為了集成分佈式應用,開發者需要對異構網絡環境下的分佈式應用提供有效的通信手段。為了管理需要共享的信息,對應用提供公共的信息交換機制是重要的。常用的消息隊列技術是 Message Queue。

Message Queue 的通訊模式

  1. 點對點通訊:點對點方式是最為傳統和常見的通訊方式,它支持一對一、一對多、多對多、多對一等多種配置方式,支持樹狀、網狀等多種拓撲結構。
  2. 多點廣播:MQ 適用於不同類型的應用。其中重要的,也是正在發展中的是"多點廣播"應用,即能夠將消息發送到多個目標站點 (Destination List)。可以使用一條 MQ 指令將單一消息發送到多個目標站點,並確保為每一站點可靠地提供信息。MQ 不僅提供了多點廣播的功能,而且還擁有智能消息分發功能,在將一條消息發送到同一系統上的多個用戶時,MQ 將消息的一個複製版本和該系統上接收者的名單發送到目標 MQ 系統。目標 MQ 系統在本地複製這些消息,並將它們發送到名單上的隊列,從而儘可能減少網絡的傳輸量。
  3. 發佈/訂閱 (Publish/Subscribe) 模式:發佈/訂閱功能使消息的分發可以突破目的隊列地理指向的限制,使消息按照特定的主題甚至內容進行分發,用戶或應用程序可以根據主題或內容接收到所需要的消息。發佈/訂閱功能使得發送者和接收者之間的耦合關係變得更為鬆散,發送者不必關心接收者的目的地址,而接收者也不必關心消息的發送地址,而只是根據消息的主題進行消息的收發。
  4. 群集 (Cluster):為了簡化點對點通訊模式中的系統配置,MQ 提供 Cluster(群集) 的解決方案。群集類似於一個域 (Domain),群集內部的隊列管理器之間通訊時,不需要兩兩之間建立消息通道,而是採用群集 (Cluster) 通道與其它成員通訊,從而大大簡化了系統配置。此外,群集中的隊列管理器之間能夠自動進行負載均衡,當某一隊列管理器出現故障時,其它隊列管理器可以接管它的工作,從而大大提高系統的高可靠性。

Apache Kafka 原理

Kafka 是一個消息系統,原本開發自 LinkedIn,用作 LinkedIn 的活動流(Activity Stream)和運營數據處理管道(Pipeline)的基礎。現在它已被多家公司作為多種類型的數據管道和消息系統使用。活動流數據是幾乎所有站點在對其網站使用情況做報表時都要用到的數據中最常規的部分。活動數據包括頁面訪問量(Page View)、被查看內容方面的信息以及搜索情況等內容。這種數據通常的處理方式是先把各種活動以日誌的形式寫入某種文件,然後週期性地對這些文件進行統計分析。運營數據指的是服務器的性能數據(CPU、IO 使用率、請求時間、服務日誌等等數據),總的來說,運營數據的統計方法種類繁多。

  • Kafka 專用術語

Broker:Kafka 集群包含一個或多個服務器,這種服務器被稱為 broker。

Topic:每條發佈到 Kafka 集群的消息都有一個類別,這個類別被稱為 Topic。(物理上不同 Topic 的消息分開存儲,邏輯上一個 Topic 的消息雖然保存於一個或多個 broker 上,但用戶只需指定消息的 Topic 即可生產或消費數據而不必關心數據存於何處)。

Partition:Partition 是物理上的概念,每個 Topic 包含一個或多個 Partition。

Producer:負責發佈消息到 Kafka broker。

Consumer:消息消費者,向 Kafka broker 讀取消息的客戶端。

Consumer Group:每個 Consumer 屬於一個特定的 Consumer Group(可為每個 Consumer 指定 group name,若不指定 group name 則屬於默認的 group)。

  • Kafka 交互流程

Kafka 是一個基於分佈式的消息發佈-訂閱系統,它被設計成快速、可擴展的、持久的。與其他消息發佈-訂閱系統類似,Kafka 在主題當中保存消息的信息。生產者向主題寫入數據,消費者從主題讀取數據。由於 Kafka 的特性是支持分佈式,同時也是基於分佈式的,所以主題也是可以在多個節點上被分區和覆蓋的。

信息是一個字節數組,程序員可以在這些字節數組中存儲任何對象,支持的數據格式包括 String、JSON、Avro。Kafka 通過給每一個消息綁定一個鍵值的方式來保證生產者可以把所有的消息發送到指定位置。屬於某一個消費者群組的消費者訂閱了一個主題,通過該訂閱消費者可以跨節點地接收所有與該主題相關的消息,每一個消息只會發送給群組中的一個消費者,所有擁有相同鍵值的消息都會被確保發給這一個消費者。

Kafka 設計中將每一個主題分區當作一個具有順序排列的日誌。同處於一個分區中的消息都被設置了一個唯一的偏移量。Kafka 只會保持跟蹤未讀消息,一旦消息被置為已讀狀態,Kafka 就不會再去管理它了。Kafka 的生產者負責在消息隊列中對生產出來的消息保證一定時間的佔有,消費者負責追蹤每一個主題 (可以理解為一個日誌通道) 的消息並及時獲取它們。基於這樣的設計,Kafka 可以在消息隊列中保存大量的開銷很小的數據,並且支持大量的消費者訂閱。

利用 Apache Kafka 系統架構的設計思路

  • 示例:網絡遊戲

假設我們正在開發一個在線網絡遊戲平臺,這個平臺需要支持大量的在線用戶實時操作,玩家在一個虛擬的世界裡通過互相協作的方式一起完成每一個任務。由於遊戲當中允許玩家互相交易金幣、道具,我們必須確保玩家之間的誠信關係,而為了確保玩家之間的誠信及賬戶安全,我們需要對玩家的 IP 地址進行追蹤,當出現一個長期固定 IP 地址忽然之間出現異動情況,我們要能夠預警,同時,如果出現玩家所持有的金幣、道具出現重大變更的情況,也要能夠及時預警。此外,為了讓開發組的數據工程師能夠測試新的算法,我們要允許這些玩家數據進入到 Hadoop 集群,即加載這些數據到 Hadoop 集群裡面。

對於一個實時遊戲,我們必須要做到對存儲在服務器內存中的數據進行快速處理,這樣可以幫助實時地發出預警等各類動作。我們的系統架設擁有多臺服務器,內存中的數據包括了每一個在線玩家近 30 次訪問的各類記錄,包括道具、交易信息等等,並且這些數據跨服務器存儲。

我們的服務器擁有兩個角色:首先是接受用戶發起的動作,例如交易請求,其次是實時地處理用戶發起的交易並根據交易信息發起必要的預警動作。為了保證快速、實時地處理數據,我們需要在每一臺機器的內存中保留歷史交易信息,這意味著我們必須在服務器之間傳遞數據,即使接收用戶請求的這臺機器沒有該用戶的交易信息。為了保證角色的鬆耦合,我們使用 Kafka 在服務器之間傳遞信息 (數據)。

  • Kafka 特性

Kafka 的幾個特性非常滿足我們的需求:可擴展性、數據分區、低延遲、處理大量不同消費者的能力。這個案例我們可以配置在 Kafka 中為登陸和交易配置同一個主題。由於 Kafka 支持在單一主題內的排序,而不是跨主題的排序,所以我們為了保證用戶在交易前使用實際的 IP 地址登陸系統,我們採用了同一個主題來存儲登陸信息和交易信息。

當用戶登陸或者發起交易動作後,負責接收的服務器立即發事件給 Kafka。這裡我們採用用戶 id 作為消息的主鍵,具體事件作為值。這保證了同一個用戶的所有的交易信息和登陸信息被髮送到 Kafka 分區。每一個事件處理服務被當作一個 Kafka 消費者來運行,所有的消費者被配置到了同一個消費者群組,這樣每一臺服務器從一些 Kafka 分區讀取數據,一個分區的所有數據被送到同一個事件處理服務器 (可以與接收服務器不同)。當事件處理服務器從 Kafka 讀取了用戶交易信息,它可以把該信息加入到保存在本地內存中的歷史信息列表裡面,這樣可以保證事件處理服務器在本地內存中調用用戶的歷史信息並做出預警,而不需要額外的網絡或磁盤開銷。

圖 1. 遊戲設計圖

Apache kafka 工作原理介紹

>為了多線程處理,我們為每一個事件處理服務器或者每一個核創建了一個分區。Kafka 已經在擁有 1 萬個分區的集群裡測試過。

  • 切換回 Kafka

上面的例子聽起來有點繞口:首先從遊戲服務器發送信息到 Kafka,然後另一臺遊戲服務器的消費者從主題中讀取該信息並處理它。然而,這樣的設計解耦了兩個角色並且允許我們管理每一個角色的各種功能。此外,這種方式不會增加負載到 Kafka。測試結果顯示,即使 3 個結點組成的集群也可以處理每秒接近百萬級的任務,平均每個任務從註冊到消費耗時 3 毫秒。

上面例子當發現一個事件可疑後,發送一個預警標誌到一個新的 Kafka 主題,同樣的有一個消費者服務會讀取它,並將數據存入 Hadoop 集群用於進一步的數據分析。

因為 Kafka 不會追蹤消息的處理過程及消費者隊列,所以它在消耗極小的前提下可以同時處理數千個消費者。Kafka 甚至可以處理批量級別的消費者,例如每小時喚醒一次一批睡眠的消費者來處理所有的信息。

Kafka 讓數據存入 Hadoop 集群變得非常簡單。當擁有多個數據來源和多個數據目的地時,為每一個來源和目的地配對地編寫一個單獨的數據通道會導致混亂髮生。Kafka 幫助 LinkedIn 規範了數據通道格式,並且允許每一個系統獲取數據和寫入數據各一次,這樣極大地減少數據通道的複雜性和操作耗時。

LinkedIn 的架構師 Jay Kreps 說:“我最初是在 2008 年完成鍵值對數據存儲方式後開始的,我的項目是嘗試運行 Hadoop,將我們的一些處理過程移動到 Hadoop 裡面去。我們在這個領域幾乎沒有經驗,花了幾個星期嘗試把數據導入、導出,另外一些事件花在了嘗試各種各樣的預測性算法使用上面,然後,我們開始了漫漫長路”。

  • 與 Flume 的區別

Kafka 與 Flume 很多功能確實是重複的。以下是評估兩個系統的一些建議:

  1. Kafka 是一個通用型系統。你可以有許多的生產者和消費者分享多個主題。相反地,Flume 被設計成特定用途的工作,特定地向 HDFS 和 HBase 發送出去。Flume 為了更好地為 HDFS 服務而做了特定的優化,並且與 Hadoop 的安全體系整合在了一起。基於這樣的結論,Hadoop 開發商 Cloudera 推薦如果數據需要被多個應用程序消費的話,推薦使用 Kafka,如果數據只是面向 Hadoop 的,可以使用 Flume。
  2. Flume 擁有許多配置的來源 (sources) 和存儲池 (sinks)。然後,Kafka 擁有的是非常小的生產者和消費者環境體系,Kafka 社區並不是非常支持這樣。如果你的數據來源已經確定,不需要額外的編碼,那你可以使用 Flume 提供的 sources 和 sinks,反之,如果你需要準備自己的生產者和消費者,那你需要使用 Kafka。
  3. Flume 可以在攔截器裡面實時處理數據。這個特性對於過濾數據非常有用。Kafka 需要一個外部系統幫助處理數據。
  4. 無論是 Kafka 或是 Flume,兩個系統都可以保證不丟失數據。然後,Flume 不會複製事件。相應地,即使我們正在使用一個可以信賴的文件通道,如果 Flume agent 所在的這個節點宕機了,你會失去所有的事件訪問能力直到你修復這個受損的節點。使用 Kafka 的管道特性不會有這樣的問題。
  5. Flume 和 Kafka 可以一起工作的。如果你需要把流式數據從 Kafka 轉移到 Hadoop,可以使用 Flume 代理 (agent),將 kafka 當作一個來源 (source),這樣可以從 Kafka 讀取數據到 Hadoop。你不需要去開發自己的消費者,你可以使用 Flume 與 Hadoop、HBase 相結合的特性,使用 Cloudera Manager 平臺監控消費者,並且通過增加過濾器的方式處理數據。

結束語

綜上所述,Kafka 的設計可以幫助我們解決很多架構上的問題。但是想要用好 Kafka 的高性能、低耦合、高可靠性、數據不丟失等特性,我們需要非常瞭解 Kafka,以及我們自身的應用系統使用場景,並不是任何環境 Kafka 都是最佳選擇。

相關推薦

推薦中...