當前位置:編程學習大全網 - 源碼下載 - Kafka架構及基本原理簡析

Kafka架構及基本原理簡析

?Kafka是壹個由Scala和Java編寫的企業級的消息發布和訂閱系統,最早是由Linkedin公司開發,最終開源到Apache軟件基金會的項目。Kafka是壹個分布式的,支持分區的,多副本的和多訂閱者的高吞吐量的消息系統,被廣泛應用在應用解耦、異步處理、限流削峰和消息驅動等場景。本文將針對Kafka的架構和相關組件進行簡單的介紹。在介紹Kafka的架構之前,我們先了解壹下Kafk的核心概念。

?在詳細介紹Kafka的架構和基本組件之前,需要先了解壹下Kafka的壹些核心概念。

Producer: 消息的生產者,負責往Kafka集群中發送消息;

Consumer: 消息的消費者,主動從Kafka集群中拉取消息。

Consumer Group: 每個Consumer屬於壹個特定的Consumer Group,新建Consumer的時候需要指定對應的Consumer Group ID。

Broker: Kafka集群中的服務實例,也稱之為節點,每個Kafka集群包含壹個或者多個Broker(壹個Broker就是壹個服務器或節點)。

Message: 通過Kafka集群進行傳遞的對象實體,存儲需要傳送的信息。

Topic: 消息的類別,主要用於對消息進行邏輯上的區分,每條發送到Kafka集群的消息都需要有壹個指定的Topic,消費者根據Topic對指定的消息進行消費。

Partition: 消息的分區,Partition是壹個物理上的概念,相當於壹個文件夾,Kafka會為每個topic的每個分區創建壹個文件夾,壹個Topic的消息會存儲在壹個或者多個Partition中。

Segment: 壹個partition當中存在多個segment文件段(分段存儲),每個Segment分為兩部分,.log文件和 .index 文件,其中 .index 文件是索引文件,主要用於快速查詢.log 文件當中數據的偏移量位置;

.log文件: 存放Message的數據文件,在Kafka中把數據文件就叫做日誌文件。壹個分區下面默認有n多個.log文件(分段存儲)。壹個.log文件大默認1G,消息會不斷追加在.log文件中,當.log文件的大小超過1G的時候,會自動新建壹個新的.log文件。

.index文件: 存放.log文件的索引數據,每個.index文件有壹個對應同名的.log文件。

?後面我們會對上面的壹些核心概念進行更深入的介紹。在介紹完Kafka的核心概念之後,我們來看壹下Kafka的對外提供的基本功能,組件及架構設計。

?如上圖所示,Kafka主要包含四個主要的API組件:

1. Producer API

?應用程序通過Producer API向Kafka集群發送壹個或多個Topic的消息。

2. Consumer API

?應用程序通過Consumer API,向Kafka集群訂閱壹個或多個Topic的消息,並處理這些Topic下接收到的消息。

3. Streams API

?應用程序通過使用Streams API充當流處理器(Stream Processor),從壹個或者多個Topic獲取輸入流,並生產壹個輸出流到壹個或者多個Topic,能夠有效地將輸入流進行轉變後變成輸出流輸出到Kafka集群。

4. Connect API

?允許應用程序通過Connect API構建和運行可重用的生產者或者消費者,能夠把kafka主題連接到現有的應用程序或數據系統。Connect實際上就做了兩件事情:使用Source Connector從數據源(如:DB)中讀取數據寫入到Topic中,然後再通過Sink Connector讀取Topic中的數據輸出到另壹端(如:DB),以實現消息數據在外部存儲和Kafka集群之間的傳輸。

?接下來我們將從Kafka的架構出發,重點介紹Kafka的主要組件及實現原理。Kafka支持消息持久化,消費端是通過主動拉取消息進行消息消費的,訂閱狀態和訂閱關系由客戶端負責維護,消息消費完後不會立刻刪除,會保留歷史消息,壹般默認保留7天,因此可以通過在支持多訂閱者時,消息無需復制多分,只需要存儲壹份就可以。下面將詳細介紹每個組件的實現原理。

1. Producer

?Producer是Kafka中的消息生產者,主要用於生產帶有特定Topic的消息,生產者生產的消息通過Topic進行歸類,保存在Kafka 集群的Broker上,具體的是保存在指定的partition 的目錄下,以Segment的方式(.log文件和.index文件)進行存儲。

2. Consumer

?Consumer是Kafka中的消費者,主要用於消費指定Topic的消息,Consumer是通過主動拉取的方式從Kafka集群中消費消息,消費者壹定屬於某壹個特定的消費組。

3. Topic

?Kafka中的消息是根據Topic進行分類的,Topic是支持多訂閱的,壹個Topic可以有多個不同的訂閱消息的消費者。Kafka集群Topic的數量沒有限制,同壹個Topic的數據會被劃分在同壹個目錄下,壹個Topic可以包含1至多個分區,所有分區的消息加在壹起就是壹個Topic的所有消息。

4. Partition

?在Kafka中,為了提升消息的消費速度,可以為每個Topic分配多個Partition,這也是就之前我們說到的,Kafka是支持多分區的。默認情況下,壹個Topic的消息只存放在壹個分區中。Topic的所有分區的消息合並起來,就是壹個Topic下的所有消息。每個分區都有壹個從0開始的編號,每個分區內的數據都是有序的,但是不同分區直接的數據是不能保證有序的,因為不同的分區需要不同的Consumer去消費,每個Partition只能分配壹個Consumer,但是壹個Consumer可以同時壹個Topic的多個Partition。

5. Consumer Group

?Kafka中的每壹個Consumer都歸屬於壹個特定的Consumer Group,如果不指定,那麽所有的Consumer都屬於同壹個默認的Consumer Group。Consumer Group由壹個或多個Consumer組成,同壹個Consumer Group中的Consumer對同壹條消息只消費壹次。每個Consumer Group都有壹個唯壹的ID,即Group ID,也稱之為Group Name。Consumer Group內的所有Consumer協調在壹起訂閱壹個Topic的所有Partition,且每個Partition只能由壹個Consuemr Group中的壹個Consumer進行消費,但是可以由不同的Consumer Group中的壹個Consumer進行消費。如下圖所示:

在層級關系上來說Consumer Group好比是跟Topic對應的,而Consumer就對應於Topic下的Partition。Consumer Group中的Consumer數量和Topic下的Partition數量***同決定了消息消費的並發量,且Partition數量決定了最終並發量,因為壹個Partition只能由壹個Consumer進行消費。當壹個Consumer Group中Consumer數量超過訂閱的Topic下的Partition數量時,Kafka會為每個Partition分配壹個Consumer,多出來的Consumer會處於空閑狀態。當Consumer Group中Consumer數量少於當前定於的Topic中的Partition數量是,單個Consumer將承擔多個Partition的消費工作。如上圖所示,Consumer Group B中的每個Consumer需要消費兩個Partition中的數據,而Consumer Group C中會多出來壹個空閑的Consumer4。總結下來就是:同壹個Topic下的Partition數量越多,同壹時間可以有越多的Consumer進行消費,消費的速度就會越快,吞吐量就越高。同時,Consumer Group中的Consumer數量需要控制為小於等於Partition數量,且最好是整數倍:如1,2,4等。

6. Segment

?考慮到消息消費的性能,Kafka中的消息在每個Partition中是以分段的形式進行存儲的,即每1G消息新建壹個Segment,每個Segment包含兩個文件:.log文件和.index文件。之前我們已經說過,.log文件就是Kafka實際存儲Producer生產的消息,而.index文件采用稀疏索引的方式存儲.log文件中對應消息的邏輯編號和物理偏移地址(offset),以便於加快數據的查詢速度。.log文件和.index文件是壹壹對應,成對出現的。下圖展示了.log文件和.index文件在Partition中的存在方式。

?Kafka裏面每壹條消息都有自己的邏輯offset(相對偏移量)以及存在物理磁盤上面實際的物理地址便宜量Position,也就是說在Kafka中壹條消息有兩個位置:offset(相對偏移量)和position(磁盤物理偏移地址)。在kafka的設計中,將消息的offset作為了Segment文件名的壹部分。Segment文件命名規則為:Partition全局的第壹個Segment從0開始,後續每個segment文件名為上壹個Partition的最大offset(Message的offset,非實際物理地偏移地址,實際物理地址需映射到.log中,後面會詳細介紹在.log文件中查詢消息的原理)。數值最大為64位long大小,由20位數字表示,前置用0填充。

?上圖展示了.index文件和.log文件直接的映射關系,通過上圖,我們可以簡單介紹壹下Kafka在Segment中查找Message的過程:

? 1. 根據需要消費的下壹個消息的offset,這裏假設是7,使用二分查找在Partition中查找到文件名小於(壹定要小於,因為文件名編號等於當前offset的文件裏存的都是大於當前offset的消息)當前offset的最大編號的.index文件,這裏自然是查找到了00000000000000000000.index。

? 2. 在.index文件中,使用二分查找,找到offset小於或者等於指定offset(這裏假設是7)的最大的offset,這裏查到的是6,然後獲取到index文件中offset為6指向的Position(物理偏移地址)為258。

? 3. 在.log文件中,從磁盤位置258開始順序掃描,直到找到offset為7的Message。

至此,我們就簡單介紹完了Segment的基本組件.index文件和.log文件的存儲和查詢原理。但是我們會發現壹個問題:.index文件中的offset並不是按順序連續存儲的,為什麽Kafka要將索引文件設計成這種不連續的樣子?這種不連續的索引設計方式稱之為稀疏索引,Kafka中采用了稀疏索引的方式讀取索引,kafka每當.log中寫入了4k大小的數據,就往.index裏以追加的寫入壹條索引記錄。使用稀疏索引主要有以下原因:

? (1) 索引稀疏存儲,可以大幅降低.index文件占用存儲空間大小。

? (2) 稀疏索引文件較小,可以全部讀取到內存中,可以避免讀取索引的時候進行頻繁的IO磁盤操作,以便通過索引快速地定位到.log文件中的Message。

7. Message

?Message是實際發送和訂閱的信息是實際載體,Producer發送到Kafka集群中的每條消息,都被Kafka包裝成了壹個Message對象,之後再存儲在磁盤中,而不是直接存儲的。Message在磁盤中的物理結構如下所示。

?其中 key 和 value 存儲的是實際的Message內容,長度不固定,而其他都是對Message內容的統計和描述,長度固定。因此在查找實際Message過程中,磁盤指針會根據Message的 offset 和 message length 計算移動位數,以加速Message的查找過程。之所以可以這樣加速,因為Kafka的.log文件都是順序寫的,往磁盤上寫數據時,就是追加數據,沒有隨機寫的操作。

8.Partition Replicas

?最後我們簡單聊壹下Kafka中的Partition Replicas(分區副本)機制,0.8版本以前的Kafka是沒有副本機制的。創建Topic時,可以為Topic指定分區,也可以指定副本個數。kafka 中的分區副本如下圖所示:

?Kafka通過副本因子(replication-factor)控制消息副本保存在幾個Broker(服務器)上,壹般情況下副本數等於Broker的個數,且同壹個副本因子不能放在同壹個Broker中。副本因子是以分區為單位且區分角色;主副本稱之為Leader(任何時刻只有壹個),從副本稱之為 Follower(可以有多個),處於同步狀態的副本叫做in-sync-replicas(ISR)。Leader負責讀寫數據,Follower不負責對外提供數據讀寫,只從Leader同步數據,消費者和生產者都是從leader讀寫數據,不與follower交互,因此Kafka並不是讀寫分離的。同時使用Leader進行讀寫的好處是,降低了數據同步帶來的數據讀取延遲,因為Follower只能從Leader同步完數據之後才能對外提供讀取服務。

?如果壹個分區有三個副本因子,就算其中壹個掛掉,那麽只會剩下的兩個中,選擇壹個leader,如下圖所示。但不會在其他的broker中,另啟動壹個副本(因為在另壹臺啟動的話,必然存在數據拷貝和傳輸,會長時間占用網絡IO,Kafka是壹個高吞吐量的消息系統,這個情況不允許發生)。如果指定分區的所有副本都掛了,Consumer如果發送數據到指定分區的話,將寫入不成功。Consumer發送到指定Partition的消息,會首先寫入到Leader Partition中,寫完後還需要把消息寫入到ISR列表裏面的其它分區副本中,寫完之後這個消息才能提交offset。

?到這裏,差不多把Kafka的架構和基本原理簡單介紹完了。Kafka為了實現高吞吐量和容錯,還引入了很多優秀的設計思路,如零拷貝,高並發網絡設計,順序存儲,以後有時間再說。

  • 上一篇:微信聊天記錄下data是什麽文件
  • 下一篇:如何移植android2.1源代碼到自己的手機上
  • copyright 2024編程學習大全網