轉載-阿里大牛實戰歸納——Kafka架構原理

閱讀本篇博客主要學習到的內容:

  1. 一個topic被分割成多個分片(Partition),分片內內容按照順序進行存儲。生產者根據Key值來決定將消息發送到哪個分片:1)如果沒有Key值,則進行輪訓發送 2)有key值,對Key值進行hash,然後對分區數量取餘,如果想要數據的強烈順序性,可以讓該的消息都設置一個Key。
  2. 每個topic下面的所有消息,都是以分片的形式存儲在多個節點上。同時每個分片都會對應一個日誌目錄,每個日誌目錄下對應多個日誌分段(LogSegemnt,由.index 索引文件和.log 數據文件 兩個文件構成)。第一個segment從0開始後續每個segment的的文件名爲上一個segment的文件的最後一條消息的Offset。
  3. 我們對kafka消息進行消費的時候,一般是按照順序讀即可,順序讀會使用計算機的預讀功能,所以順序讀寫很快。但是kafuka的分區過多以後,會導致寫的時候變成了隨機寫,隨機IO對性能影響很大,所以每個topic不宜設置過多的分片???這一點有待去查資料驗證。
  4. 每個分片都會有0或者多個副本,副本和主節點採用異步同步。當主節點故障,通過ZK選舉的模式來選出新的Leader,同時被選舉的副本不能落後主節點太多。
  5. kafk的消費模型兩種方式:push和pull。Push模型容易出現消息丟失問題,而且如果生產者掛掉了,會容易造成阻塞。pull模型由消費者自己控制速度,性能對比?
  6. 當producer像Leader發送數據的時候,有三種模式可以設置request.required.acks:1(默認)主分片成功收到數據後並得到確認纔會發送下一條。leader宕機後有可能會丟失  0:不需要等待broker確認直接發送,傳輸效率最高,數據可靠性最低。-1: 確保所有主節點和副節點都確認收到消息後才發送嚇一跳,可靠性最高,保證了數據不丟失,但是吞吐量會下降。

 

阿里大牛實戰歸納——Kafka架構原理

Java高級互聯網架構 2019-09-27 15:55:54

 

阿里大牛實戰歸納——Kafka架構原理

 

 

對於kafka的架構原理我們先提出幾個問題?

· 1.Kafka的topic和分區內部是如何存儲的,有什麼特點?

· 2.與傳統的消息系統相比,Kafka的消費模型有什麼優點?

· 3.Kafka如何實現分佈式的數據存儲與數據讀取?

Kafka架構圖

 

阿里大牛實戰歸納——Kafka架構原理

 

 

1.kafka名詞解釋

在一套kafka架構中有多個Producer,多個Broker,多個Consumer,每個Producer可以對應多個Topic,每個Consumer只能對應一個ConsumerGroup。

整個Kafka架構對應一個ZK集羣,通過ZK管理集羣配置,選舉Leader,以及在consumer group發生變化時進行rebalance。

名稱解釋

Broker

消息中間件處理節點,一個Kafka節點就是一個broker,一個或者多個Broker可以組成一個Kafka集羣

Topic

主題,Kafka根據topic對消息進行歸類,發佈到Kafka集羣的每條消息都需要指定一個topic

Producer

消息生產者,向Broker發送消息的客戶端

Consumer

消息消費者,從Broker讀取消息的客戶端

ConsumerGroup

每個Consumer屬於一個特定的Consumer Group,一條消息可以發送到多個不同的Consumer Group,但是一個Consumer Group中只能有一個Consumer能夠消費該消息

Partition

物理上的概念,一個topic可以分爲多個partition,每個partition內部是有序的

2.Topic和Partition

在Kafka中的每一條消息都有一個topic。一般來說在我們應用中產生不同類型的數據,都可以設置不同的主題。一個主題一般會有多個消息的訂閱者,當生產者發佈消息到某個主題時,訂閱了這個主題的消費者都可以接收到生產者寫入的新消息。

kafka爲每個主題維護了分佈式的分區(partition)日誌文件,每個partition在kafka存儲層面是append log。任何發佈到此partition的消息都會被追加到log文件的尾部,在分區中的每條消息都會按照時間順序分配到一個單調遞增的順序編號,也就是我們的offset,offset是一個long型的數字,我們通過這個offset可以確定一條在該partition下的唯一消息。在partition下面是保證了有序性,但是在topic下面沒有保證有序性。

 

阿里大牛實戰歸納——Kafka架構原理

 

 

在上圖中在我們的生產者會決定發送到哪個Partition。

· 如果沒有Key值則進行輪詢發送。

· 如果有Key值,對Key值進行Hash,然後對分區數量取餘,保證了同一個Key值的會被路由到同一個分區,如果想隊列的強順序一致性,可以讓所有的消息都設置爲同一個Key。

3.消費模型

消息由生產者發送到kafka集羣后,會被消費者消費。一般來說我們的消費模型有兩種:推送模型(push)和拉取模型(pull)

基於推送模型的消息系統,由消息代理記錄消費狀態。消息代理將消息推送到消費者後,標記這條消息爲已經被消費,但是這種方式無法很好地保證消費的處理語義。比如當我們把已經把消息發送給消費者之後,由於消費進程掛掉或者由於網絡原因沒有收到這條消息,如果我們在消費代理將其標記爲已消費,這個消息就永久丟失了。如果我們利用生產者收到消息後回覆這種方法,消息代理需要記錄消費狀態,這種不可取。如果採用push,消息消費的速率就完全由消費代理控制,一旦消費者發生阻塞,就會出現問題。

Kafka採取拉取模型(poll),由自己控制消費速度,以及消費的進度,消費者可以按照任意的偏移量進行消費。比如消費者可以消費已經消費過的消息進行重新處理,或者消費最近的消息等等。

4.網絡模型

4.1 KafkaClient --單線程Selector

 

阿里大牛實戰歸納——Kafka架構原理

 

 

單線程模式適用於併發鏈接數小,邏輯簡單,數據量小。

在kafka中,consumer和producer都是使用的上面的單線程模式。這種模式不適合kafka的服務端,在服務端中請求處理過程比較複雜,會造成線程阻塞,一旦出現後續請求就會無法處理,會造成大量請求超時,引起雪崩。而在服務器中應該充分利用多線程來處理執行邏輯。

4.2 Kafka--server -- 多線程Selector

 

阿里大牛實戰歸納——Kafka架構原理

 

 

在kafka服務端採用的是多線程的Selector模型,Acceptor運行在一個單獨的線程中,對於讀取操作的線程池中的線程都會在selector註冊read事件,負責服務端讀取請求的邏輯。成功讀取後,將請求放入message queue共享隊列中。然後在寫線程池中,取出這個請求,對其進行邏輯處理,即使某個請求線程阻塞了,還有後續的縣城從消息隊列中獲取請求並進行處理,在寫線程中處理完邏輯處理,由於註冊了OP_WIRTE事件,所以還需要對其發送響應。

5.高可靠分佈式存儲模型

在Kafka中保證高可靠模型的依靠的是副本機制,有了副本機制之後,就算機器宕機也不會發生數據丟失。

5.1高性能的日誌存儲

kafka一個topic下面的所有消息都是以partition的方式分佈式的存儲在多個節點上。同時在kafka的機器上,每個Partition其實都會對應一個日誌目錄,在目錄下面會對應多個日誌分段(LogSegment)。LogSegment文件由兩部分組成,分別爲“.index”文件和“.log”文件,分別表示爲segment索引文件和數據文件。這兩個文件的命令規則爲:partition全局的第一個segment從0開始,後續每個segment文件名爲上一個segment文件最後一條消息的offset值,數值大小爲64位,20位數字字符長度,沒有數字用0填充,如下,假設有1000條消息,每個LogSegment大小爲100,下面展現了900-1000的索引和Log:

 

阿里大牛實戰歸納——Kafka架構原理

 

 

由於kafka消息數據太大,如果全部建立索引,即佔了空間又增加了耗時,所以kafka選擇了稀疏索引的方式,這樣的話索引可以直接進入內存,加快偏查詢速度。

簡單介紹一下如何讀取數據,如果我們要讀取第911條數據首先第一步,找到他是屬於哪一段的,根據二分法查找到他屬於的文件,找到0000900.index和00000900.log之後,然後去index中去查找 (911-900) =11這個索引或者小於11最近的索引,在這裏通過二分法我們找到了索引是[10,1367]然後我們通過這條索引的物理位置1367,開始往後找,直到找到911條數據。

上面講的是如果要找某個offset的流程,但是我們大多數時候並不需要查找某個offset,只需要按照順序讀即可,而在順序讀中,操作系統會對內存和磁盤之間添加page cahe,也就是我們平常見到的預讀操作,所以我們的順序讀操作時速度很快。但是kafka有個問題,如果分區過多,那麼日誌分段也會很多,寫的時候由於是批量寫,其實就會變成隨機寫了,隨機I/O這個時候對性能影響很大。所以一般來說Kafka不能有太多的partition。針對這一點,RocketMQ把所有的日誌都寫在一個文件裏面,就能變成順序寫,通過一定優化,讀也能接近於順序讀。

可以思考一下:

1.爲什麼需要分區,也就是說主題只有一個分區,難道不行嗎?2.日誌爲什麼需要分段

5.2副本機制

Kafka的副本機制是多個服務端節點對其他節點的主題分區的日誌進行復制。當集羣中的某個節點出現故障,訪問故障節點的請求會被轉移到其他正常節點(這一過程通常叫Reblance),kafka每個主題的每個分區都有一個主副本以及0個或者多個副本,副本保持和主副本的數據同步,當主副本出故障時就會被替代。

 

阿里大牛實戰歸納——Kafka架構原理

 

 

在Kafka中並不是所有的副本都能被拿來替代主副本,所以在kafka的leader節點中維護着一個ISR(In sync Replicas)集合,翻譯過來也叫正在同步中集合,在這個集合中的需要滿足兩個條件:

· 節點必須和ZK保持連接

· 在同步的過程中這個副本不能落後主副本太多

另外還有個AR(Assigned Replicas)用來標識副本的全集,OSR用來表示由於落後被剔除的副本集合,所以公式如下:ISR = leader + 沒有落後太多的副本; AR = OSR+ ISR;

這裏先要說下兩個名詞:HW(高水位)是consumer能夠看到的此partition的位置,LEO是每個partition的log最後一條Message的位置。HW能保證leader所在的broker失效,該消息仍然可以從新選舉的leader中獲取,不會造成消息丟失。

當producer向leader發送數據時,可以通過request.required.acks參數來設置數據可靠性的級別:

· 1(默認):這意味着producer在ISR中的leader已成功收到的數據並得到確認後發送下一條message。如果leader宕機了,則會丟失數據。

· 0:這意味着producer無需等待來自broker的確認而繼續發送下一批消息。這種情況下數據傳輸效率最高,但是數據可靠性確是最低的。

· -1:producer需要等待ISR中的所有follower都確認接收到數據後纔算一次發送完成,可靠性最高。但是這樣也不能保證數據不丟失,比如當ISR中只有leader時(其他節點都和zk斷開連接,或者都沒追上),這樣就變成了acks=1的情況。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章