女朋友看了也懂的Kafka(上篇)

流年細品溫如言發表於2021-06-06

@

前言:為什麼需要Kafka

舉個例子:麥當勞點餐時,當我們選擇外帶的時候,餐廳製作好餐之後會放在一個取餐檯,而且取餐檯是按照不同的取餐碼尾號分開放置的,按照餐品的產出順序進行放置的。這時候我們可以在我們空閒的時候去取餐,而餐廳也不用等待我們拿完餐再生產。而這個取餐檯就像一個訊息佇列。我們現在想想如果沒有這個取餐檯會發生什麼?餐廳不斷需要顧客及時取走,不然會嚴重影響到餐廳的出餐和訂單處理。那消費者也要關注取餐的資訊,自己的時間安排自由度就下降了。so,取餐檯這個中間緩衝的物件就可以接觸消費者和餐廳的強繫結關係,讓餐廳和消費者都可以自由化做各自的事情。

Kafka所扮演的角色就是類似當前取餐檯的功能,當然起作用不僅僅是緩衝,在接下來的內容中一起揭開kafka的面紗,一窺其工作機理和設計思想。

1.初識kafka

我們先來看看Kafka是怎麼定義的?

kafka是一個分散式的基於釋出/訂閱模式的訊息佇列。

那啥是訊息佇列啊。如我們開篇講到的那個取餐檯就是一個訊息佇列。就是在訊息傳輸過程中儲存訊息的容器。其本質就是:

訊息傳送者(我們稱之為生產者,多形象)——>MQ(message queue訊息佇列,訊息儲存的容器)——>訊息接受者(訊息的消費者)

訊息佇列就是可以接受生產者傳送的訊息並儲存起來,佇列Queue,按照訊息接受的順序儲存,然後等待消費者進行消費訊息。訊息佇列的作用就是儲存訊息並轉發訊息。

1.1 訊息佇列的好處:

1)解耦

允許我們獨立的擴充套件或修改兩邊的處理過程,只要確保它們遵守同樣的介面約束。

2)可恢復性

系統的一部分元件失效時,不會影響到整個系統。訊息佇列降低了程式間的耦合度,所以即使一個處理訊息的程式掛掉,加入佇列中的訊息仍然可以在系統恢復後被處理。

3)緩衝

有助於控制和優化資料流經過系統的速度,解決生產訊息和消費訊息的處理速度不一致的情況。

4)靈活性 & 峰值處理能力 (削峰)

在訪問量劇增的情況下,應用仍然需要繼續發揮作用,但是這樣的突發流量並不常見。如果為以能處理這類峰值訪問為標準來投入資源隨時待命無疑是巨大的浪費。使用訊息佇列能夠使關鍵元件頂住突發的訪問壓力,而不會因為突發的超負荷的請求而完全崩潰。比如:618,雙十一等活動,00:00 大量的手速點選訪問,如果沒有訊息佇列作為緩衝,所有請求都打到Redis,mysql等伺服器,他們也扛不住啊。

5)非同步通訊

很多時候,使用者不想也不需要立即處理訊息。訊息佇列提供了非同步處理機制,允許使用者把一個訊息放入佇列,但並不立即處理它。想向佇列中放入多少訊息就放多少,然後在需要的時候再去處理它們。

1.2 訊息佇列的兩種模式

(1)點對點模式(一對一,消費者主動拉取資料,訊息收到後訊息清除)

訊息生產者生產訊息傳送到Queue中,然後訊息消費者從Queue中取出並且消費訊息。

訊息被消費以後,queue中不再有儲存,所以訊息消費者不可能消費到已經被消費的訊息。Queue支援存在多個消費者,但是對一個訊息而言,只會有一個消費者可以消費。

在這裡插入圖片描述

2)釋出/訂閱模式(一對多,消費者消費資料之後不會清除訊息)

訊息生產者(釋出)將訊息釋出到topic中,同時有多個訊息消費者(訂閱)消費該訊息。和點對點方式不同,釋出到topic的訊息會被所有訂閱者消費。

釋出-訂閱(Publish/Subscribe)模式(又被稱為觀察者模式,屬於行為型模式的一種,它定義了一種一對多的依賴關係,讓多個觀察者物件同時監聽某一個主題物件。這個主題物件在狀態變化時,會通知所有的觀察者物件,使他們能夠自動更新自己。

在這裡插入圖片描述

我們看看傳統的MQ有什麼問題?

沒有訊息佇列我們怎麼做?

假設現在我們的應用程式需要往別處傳送監控資訊,可以直接在應用程式和另一個可以在儀表盤上顯示度量指標的應用程式之間建立連線 然後通過這個連線推送度量指標,

我們可以這樣做:

在這裡插入圖片描述

這是剛接觸監控系統時簡單問題的應對方案。過了不久,你需要分析更長時間片段的度量指標,而此時的儀表盤程式滿足不了需求,於是,你啟動了一個新的服務來接收度盤指標。該服務把度量指標儲存起來,然後進行分析。與此同時,你修改了原來的應用程式, 把度量指標同時傳送到兩個儀表盤系統上。

現在,你又多了3個可以生成度量指標 應用 程式,它們都與這兩個服務直接相連。而你的同事認為最好可以對這些服務進行輪詢以便 獲得告警功能,於是你為每一個應用程式增加了一個伺服器,用於提供度量指標。再過一陣子,有更多的應用程式出於各自的目的,都從這些伺服器獲取度主指標。這時的架構看起來就像下圖所示一樣,節點間的連線一團糟。

在這裡插入圖片描述

傳統MQ怎麼做?

我們建立一個基於釋出訂閱的訊息佇列, 用於接收來自其他應用程式的度量指標,井為其他系統提供了一個查詢伺服器。

在這裡插入圖片描述

這時候一切都看起來這麼清爽和簡單,但是當我們和度量指標進行了一輪“艱苦奮戰”之後,其他同事也要和各自的任務進行battle。另一個同事也正在跟日誌訊息奮戰。還有另一個同事正在跟蹤網站使用者的行為,為負責機器學習開發的同事提供資訊 ,同時為管理團隊生成報告。你和同事們使用相同的方式建立這些系統,解輯資訊的釋出者和訂閱者。然後發現世界好像又不美好了?看圖:

在這裡插入圖片描述

由於不同的業務任務,我們產生了多個訊息佇列進行各自業務的處理,但是這裡有很多重複的地方。而且由於不同的業務模組,開發人員需要為各自的業務指標任務維護一套內容,而且之後或許還有其他的業務需要構建新的訊息佇列進行處理,資源浪費且每天維護這些內容,出現BUG的排查等等都會帶來極大的不便性。但是又因為傳統訊息佇列中的一個訊息只能被消費一次,這時候我們就想,如果訊息佇列可以對於不同的業務的消費者看做不同的消費者,他們都可以消費訊息佇列中的訊息就可以共用這些訊息系統了。豈不是美滋滋,即便是後邊需要增加業務,也不用獨立的使用新的訊息佇列,世界又變得美好萬分。

這時候,Kafka就”閃亮登場“了

Kafka的資料按照一定的順序持久化儲存,可以按需讀取,通過對於不同的群組的消費者重新資料的消費狀態實現多消費者共同消費訊息等。具體的資料一致性保證以及生產者消費者寫入和讀取資料是怎麼進行的,在後邊的內容會與展開講述。

2. Kafka基本架構

2.1 前備知識

1.訊息和批次

Kafka 的資料單元被稱為訊息。訊息由位元組陣列組成,所以對於Kafka來說,訊息裡的資料沒有特別的格式或含義。訊息可以有一個可選的後設資料,也就是鍵。鍵也是一個位元組陣列,與訊息一樣,對於Kafka來說也沒有特殊的含義。訊息以一種可控的方式寫入不同的分割槽時,會用到鍵。最簡單的例子就是為鍵生成一個一致性雜湊值,然後使用雜湊值對主題分割槽數進行取模,為訊息選取分割槽。

\[patitionnum = mod(hash(key) , partitions) \]

這樣可以保證具有相同鍵的訊息總是被寫到相同的分割槽上。為了提高效率,訊息被分批次寫入 Kafka 。批次就是一組訊息,這些訊息屬於同一個主題和分割槽。如果每 個訊息都單獨在網路傳輸,會導致大量的網路開銷,把訊息分成批次傳輸可以減少網路開銷。不過,這要在時間延遲和吞吐量之間作出權衡:批次越大,單位時間內處理的訊息就越多,單個訊息的傳輸時間就越長。批次資料會被壓縮,這樣可以提升資料的傳輸和儲存能力,但要做更多的計算處理。

2.訊息模式

對於Kafka而言,訊息的底層是一組位元組陣列,是我們難以辨識的內容。為了更好的理解這些訊息,就有開發者提出用額外的一種結構來定義訊息內容。比如常見的JSON和XML。這些結構不僅易用,且可讀性好。Kafka一般採用Avro。Avro提供了一種緊湊的序列化格式,其模式和訊息體是分開的。另外Avro也是由Doug Cutting建立的哦。因為Avro的一些特性,很適合Kafka這樣的訊息佇列。消除了訊息讀寫操作之間的耦合性。

如果讀寫操作緊密地耦合在一起,訊息訂閱者需要升級應用程式才能同時處理新舊兩種資料格式。在訊息訂閱者升級了之後,訊息釋出者才能跟著升級,以便使用新的資料格式。新的 應用程式如果需要使用資料,就要與訊息釋出者發生耦合,導致開發者需要做很多繁雜操作。

preview

在對於當前架構進行拆分看待前,我們先來關注一些Kafka獨到的機制和單元:
圖片引用來自知乎老劉

2.2 架構分析

1)Producer :訊息生產者,就是向kafka broker發訊息的客戶端

生產者建立訊息。一般情況下,一個訊息會被髮布到一個特定的主題上。生產者在預設情況下把訊息均衡地分佈到主題的所有分割槽上,而並不關心特定訊息會被寫到哪個分割槽。不過,在某些情況下,生產 者會把訊息直接寫到指定的分割槽。這通常是通過訊息鍵和分割槽器來實現的,分割槽器為鍵生 成一個雜湊值,並將其對映到指定的分割槽上。這樣可以保證包含同一個鍵的訊息會被寫到 同一個分割槽上。生產者也可以使用自定義的分割槽器,根據不同的業務規則將訊息對映到分割槽。

生產者具體的一些訊息寫入細節會在下一個文章進行講述。畢竟一個篇幅如果太長,也不能做到詳盡,也怕小夥伴沒有時間看完。

2)Consumer :訊息消費者,向kafka broker取訊息的客戶端

消費者讀取訊息。消費者訂閱一個或多個主題,並按照訊息生成的順序讀取它們。消費者通過檢查訊息的偏移量來區 分已經讀取過的訊息。 偏移量是另一種後設資料,它是一個不斷遞增的整數值,在建立訊息時, Kafka 會把它新增到訊息裡。在給定的分割槽裡,每個悄息的偏移量都是唯一的。消費者把每個分割槽最後讀取的悄息偏移量儲存在 Zookeeper或Kafka 上,如果悄費者關閉或重啟,它的讀取狀態不會丟失。

消費者是消費者群組的一部分,也就是說,會有一個或多個消費者共同讀取一個主題。群組保證每個分割槽只能被一個消費者使用 。

在這裡插入圖片描述

有3消費者同時讀取1個主題。其中的兩個消費者各自讀取一個分割槽,另外一個消費者讀取其他兩個分割槽。消費者與分割槽之間的對映通常被稱為消費者對分割槽的所有權關係。

通過這種方式,消費者可以消費包含大量訊息的主題。而且,如果一個消費者失效,群組裡的其他消費者可以接管失效消費者的工作。

3)Consumer Group (CG):消費者組,由多個consumer組成。消費者組內每個消費者負責消費不同分割槽的資料,一個分割槽只能由一個組內消費者消費;消費者組之間互不影響。所有的消費者都屬於某個消費者組,即消費者組是邏輯上的一個訂閱者。

消費者組,組中有多個消費者。

​ 組中消費者的個數最好 = topic分割槽數
​ 如果消費者組中消費者個數>topic分割槽數,此時有個別消費者沒有分割槽可以消費
​ 如果消費者組中消費者個數<topic分割槽數,此時有個別消費者需要消費多個分割槽的資料

**4)Broker **:一臺kafka伺服器就是一個broker。一個叢集由多個broker組成。一個broker可以容納多個topic。

broker 接收來自生產者的訊息,為訊息設定偏移量,並提交訊息到磁碟儲存。 broker 為消費者提供服務,對讀取分割槽的請求作出響應,返 回已經提交到磁碟上的訊息。根據特定的硬體及其效能特徵,單個 broker 可以輕鬆處理數千個分割槽以及每秒百萬級的訊息量。

broker 是叢集的組成部分。每個叢集都有一個 broker 同時充當了叢集控制器的角色Collector(自動從叢集的活躍成員中選舉出來)。控制器負責管理工作,包括將分割槽分配給 broker 和監控 broker。在叢集中, 一個分割槽從屬於一個 broker, 該broker 被稱為分割槽的首領。一個分割槽可以分配給多個 broke ,這個時候會發生分割槽複製。這種複製機制為分割槽提供 了訊息冗餘,如果有一個 broker 失效,其他 broker 可以接管領導權。不過,相關的消費者和生產者都要重新連線到新的首領。

在這裡插入圖片描述

分割槽複製

5)Topic :可以理解為一個佇列,生產者和消費者面向的都是一個topic

6)Partition:為了實現擴充套件性,一個非常大的topic可以分佈到多個broker(即伺服器)上,一個topic可以分為多個partition,每個partition是一個有序的佇列;

7)Replica:副本,為保證叢集中的某個節點發生故障時,該節點上的partition資料不丟失,且kafka仍然能夠繼續工作,kafka提供了副本機制,一個topic的每個分割槽都有若干個副本,一個leader和若干個follower

8)leader:每個分割槽多個副本的“主”,生產者傳送資料的物件,以及消費者消費資料的物件都是leader。

9)follower:每個分割槽多個副本中的“從”,實時從leader中同步資料,保持和leader資料的同步。leader發生故障時,某個follower會成為新的leader。

2.3Kafka 特點

1.多個生產者

Kafka 可以無縫地支援多個生產者,不管客戶端在使用單個主題還是多個主題。所以它很適合用來從多個前端系統收集資料,並以統 的格式對外提供資料。

2.多個消費者

Kafka 也支援多個消費者從一個單獨的訊息流上讀取資料,而且消費者之間互不影響。這與其他佇列系統不同,其他佇列系統的訊息一旦被一個客戶端讀 取,其他客戶端就無法再讀取它。另外,多個消費者可以組成一個群組,它們共享一個訊息流,並保證整個群組對每個給定的訊息只處理一次。

3.基於磁碟的資料儲存

Kafka 的資料 保留特性。訊息被提交到磁碟,根據設定的保留規則進行儲存。每個主題可以設定單獨的保留規則,以便滿足不同消費者的需求,各個主題可以保留不同數量的訊息。消費者可能會因為處理速度慢或突發的流量高峰導致無陸及時讀取訊息,而持久化資料可以保證資料 不會丟失。消費者可以在進行應用程式維護時離線一小段時間,而無需擔心訊息丟失或堵塞在生產者端。消費者可以被關閉,但訊息會繼續保留在 Kafka 裡。消費者可以從上次中 斷的地方繼續處理訊息。

4.伸縮性

為了能夠輕鬆處理大量資料, Kafka 一開始就被設計成一個具有靈活伸縮性的系統。使用者在開發階段可以先使用單個 broker ,再擴充套件到包含3個 broker 的小型開發叢集,然後隨著資料量不斷增長,部署到生產環境的叢集可能包含上百個 broker 。對線上叢集進行擴充套件絲毫不影響整體系統的可用性。也就是說,一個包含多個 broker 的叢集,即使個別Broker失效,仍然可以持續地為客戶提供服務。

5.高效能

前面提到的所有特性,讓 Kafka 成為了一個高效能的釋出與訂閱訊息系統。通過橫向擴充套件生產者、消費者和 broker, Kafka 可以輕鬆處理巨大的訊息流。在處理大量資料的同時, 它還能保證亞秒級的訊息延遲。

3 總結

我們通過麥當勞的例子開始進入訊息佇列,並從點對點業務到釋出訂閱的訊息佇列以及他們存在的弊端引入Kafka。我們知道了Kafka是一個流平臺,將資料看做是持續變化和不斷增長的流,可以通過釋出和訂閱資料流,並把他們儲存起來進行處理的資料系統。我們稱之為資料系統是因為kafka有別於訊息系統的分散式部署方式,可以自由伸縮、處理企業內所有的應用程式。kafka不僅僅是傳遞訊息,其還可以資料的可複製、持久化,其保留時長由我們來進行設定。

也瞭解了Kafka的基礎架構,Kafka的組成以及自個的作用和簡單做了什麼事情。對於Kafka大致有一個比較簡單的瞭解,在下篇內容中我們將走入Kafka內部到底是做了什麼。以及生產者消費者如何寫入和消費資料的,如何在寫入和消費的時候保證的資料一致性。解決節點失效以及內部的選舉機制。

我們要仰望星空,亦需腳踏實地。怕什麼真理無窮,進一寸有一寸的歡喜。我是清風,希望這篇文章對你有幫助。如有不準確之處,還請評論區留言討論。

相關文章