高效能Kafka

小猴子_X發表於2022-02-08
一.概述

訊息佇列模式:

  • 點對點: 1:1。就是一個佇列只能由一個消費者進行消費,這個消費者消費完畢就把訊息進行刪除,不會再給別的消費者。只能消費者訊息。
  • 釋出/訂閱: 1:多
    • 訊息佇列主動推送訊息。
      • 缺點:推送速率難以適應消費速率,不知道消費者的處理效率,造成浪費。
    • 消費方主動從訊息佇列拉取訊息。
      • 缺點:訊息延遲(比如每隔2秒進行拉取,就會造成2秒的延遲),每一個消費方都處於忙迴圈,一直檢測有沒有訊息。(kafka)
        • kafka改進:使用長輪詢:消費者去 Broker 拉訊息,定義了一個超時時間,也就是說消費者去請求訊息,如果有的話馬上返回訊息,如果沒有的話消費者等著直到超時,然後再次發起拉訊息請求。不會頻繁的進行拉取。

什麼是Kafka?

  • 是一個分散式的基於釋出訂閱模式訊息佇列,主要應用於大資料實時處理領域,天然分散式。
二.Kafka基礎架構

  • Producer :訊息生產者,就是向 kafka broker 發訊息的客戶端;
  • Consumer :訊息消費者,向 kafka broker 取訊息的客戶端;  
    • Consumer Group (CG):消費者組,由多個 consumer 組成。一個消費者組消費一個topic,消費者組的每一個消費者消費一個或多個Partition。
  • Broker :一臺 kafka 伺服器就是一個 broker。一個叢集由多個 broker 組成。一個 broker 可以容納多個 topic。
  • Topic :可以理解為一個佇列,生產者和消費者面向的都是一個 topic;
    • Partition:為了實現擴充套件性,一個非常大的 topic 可以分佈到多個 broker(即伺服器)上, 一個 topic 可以分為多個 partition(每個partition分佈在不同的Broker上),每個 partition 是一個有序的佇列;
  • Replica:副本,為保證叢集中的某個節點發生故障時,該節點上的 partition 資料不丟失,且 kafka 仍然能夠繼續工作,kafka 提供了副本機制,一個 topic 的每個分割槽都有若干個副本, 一個 leader 和若干個 follower。
    • leader:每個分割槽多個副本的,生產者傳送資料的物件,以及消費者消費資料的物件都是 leader。(leader和follower都是Partition,放在不同的Broker中)
    • follower:每個分割槽多個副本中的,實時從 leader 中同步資料,保持和 leader 資料的同步。leader 發生故障時,某個 follower 會成為新的 follower。

總結:

   topic就相當於Rabbit MQ 的queue,現在把queue進行分割槽,分為多個Partition。並且一個節點只有一個主Partition。相當於可以把一個訊息可以分在不同的機器上的不同主Partition上,最後交給一個消費者組。(也可以理解為把一個topic分為不同的主partition”縱向“放在不同的機器上)。一個topic對應一個消費組,一個消費組可以接受不同的topic。
三.如何保證訊息的可靠性
要保證訊息不丟失,需要三方面都進行保證:生產者(ISRack),消費者(offset),Kafka(持久化,叢集(副本同步策略))
生產者:topic 的每個 partition 收到 producer 傳送的資料後,都需要向 producer 傳送 ack(acknowledgement 確認收到),如果 producer 收到 ack,就會進行下一輪的傳送,否則重新傳送資料。
要想每一個partition傳送ack,就需要每一個partition的follower進行同步才能傳送ack
  • 副本資料同步策略
    • 半數以上完成同步,就傳送 ack。
      • 優點:延遲低;缺點:選舉新的 leader 時,容忍 n 臺 節點的故障,需要 2n+1 個副本
    • 全部完成同步,才傳送 ack。(kafka採用)
      • 優點:選舉新的 leader 時,容忍 n 臺 節點的故障,需要 n+1 個副本;缺點:延遲高。
  • AR,ISR,OSR:AR=ISR+OSR
    • ISR:In-Sync Replicas 副本同步佇列,存放可以被同步的副本,有些follower同步時超過閾值都會被剔除出ISR(萬一有的follower當機了,不能一直等它吧),存入OSR(Outof-Sync Replicas)列表,新加入的follower也會先存放在OSR中。
    • AR:所有副本
  • ack應答機制:
    • 0:不需要等待ack返回,容易丟失資料。
    • 1:只要Leader收到資料,就進行ack。不需要等待follower都同步完成。當leader沒有同步完資料前當機,丟失資料
    • -1:等待所有的follower都同步完,再進行ack。會造成資料重複。這時候才認為一條資料被commit了(放心了)。

消費者:由於 consumer 在消費過程中可能會出現斷電當機等故障,consumer 恢復後,需要從故障前的位置的繼續消費,所以 consumer 需要實時記錄自己消費到了哪個 offset,以便故障恢復後繼續消費。Kafka就是用offset來表示消費者的消費進度到哪了,每個消費者會都有自己的offset。說白了offset就是表示消費者的消費進度
  • 在以前版本的Kafka,這個offset是由Zookeeper來管理的,後來Kafka開發者認為Zookeeper不合適大量的刪改操作,於是把offset在broker以內部topic(__consumer_offsets)的方式來儲存起來。
  • 關閉自動提交位移,在訊息被完整處理之後再手動提交位移。enable.auto.commit=false 
  • LEO:指的是每個副本最大的 offset;如下圖,leader最大的LEO到19,其他的follower還沒有同步完,leader掛了,有的follower只同步到12,有的同步到15,就會出現消費資料錯亂,所以讓消費者只能從HW的位置進行消費。這樣保證消費資料不會出現錯亂。
  • HW:指的是消費者能見到的最大的 offset,ISR 佇列中最小的 LEO。

 


Kafka:Kafka是以日誌檔案進行儲存。
  • 採用分片機制索引機制
  • topic是邏輯上的概念,Partition是物理上的概念。每一個Partition又分為好幾個Segment,每一個Segment存放2個檔案。.log.index檔案。
  • .index檔案儲存索引,log檔案儲存真正的訊息,新的訊息放在檔案尾部。
 四.Kafka為什麼那麼快?
Kafka是以日誌檔案儲存在磁碟上,但是效率還是很高,為什麼呢?我們來分析它對於讀寫的優化。
  • 寫資料:
    • 順序寫入:Kafka把資料一直追加到檔案末端,省去了大量磁頭定址的時間。
    • Memory Mapped Files:mmf 直接利用作業系統的Page來實現檔案到物理記憶體的對映,完成之後對實體記憶體的操作會直接同步到硬碟。

  • 讀資料:
    • 零拷貝:作業系統的文章有講。
    • 批量傳送:Kafka允許進行批量傳送訊息,producter傳送訊息的時候,可以將訊息快取在本地,等到了固定條件傳送到 Kafka 。
    • 資料壓縮:可以通過GZIP或Snappy格式對訊息集合進行壓縮。壓縮的好處就是減少傳輸的資料量,減輕對網路傳輸的壓力
五.其他小問題

 生產者分割槽策略:

  •  指明Partition的情況下,直接存到指明的Partition值。
  • 沒有指明Partition但是有key,將key的hash值與topic的partition數進行取餘得到Partition值
  • 輪詢:既沒有Partition又沒有key,第一次呼叫時隨機生成一個整數(後面每次呼叫在這個整數上自增),將這個值與topic可用的Partititon總數取餘得到Partititon值。

消費者分割槽策略:

  • 分配策略觸發條件:當消費者組中消費者個數發生變化(新增消費者/某一個消費者當機)的時候就會觸發分配策略。
  • 輪詢:

  •  Range(預設):按照消費者組進行劃分,先算topic組/消費者的個數,按照上面消費數量大的原則進行分配。

 

 kafka中的 zookeeper 起到什麼作用,可以不用zookeeper麼?

  • 早期版本的kafka用zk做後設資料資訊儲存,consumer的消費狀態,group的管理以及 offset的值等。考慮到和zk打交道網路的問題,效率不高,就在新版本弱化了zk的依賴。
  • broker依然依賴於ZK,zookeeper 在kafka中還用來選舉controller和檢測broker是否存活等等。

 如果leader crash時,ISR為空怎麼辦?用如下引數進行調節

  • unclean.leader.election,這個引數有兩個值:
    • true(預設):允許不同步副本成為leader,由於不同步副本的訊息較為滯後,此時成為leader,可能會出現訊息不一致的情況。
    • false:不允許不同步副本成為leader,此時如果發生ISR列表為空,會一直等待舊leader恢復,降低了可用性。

為什麼Kafka不支援讀寫分離?

  • 在Kafka中,生產者寫入訊息、消費者讀取訊息的操作都是與 leader 副本進行互動的,從 而實現的是一種主寫主讀的生產消費模型。
  • Kafka 並不支援主寫從讀,因為主寫從讀有 2 個很明顯的缺點:

    1. 資料一致性問題。資料從主節點轉到從節點必然會有一個延時的時間視窗,這個時間 視窗會導致主從節點之間的資料不一致。某一時刻,在主節點和從節點中 A 資料的值都為 X, 之後將主節點中 A 的值修改為 Y,那麼在這個變更通知到從節點之前,應用讀取從節點中的 A 資料的值並不為最新的 Y,由此便產生了資料不一致的問題。

    2. 延時問題。類似 Redis 這種元件,資料從寫入主節點到同步至從節點中的過程需要經 歷網路→主節點記憶體→網路→從節點記憶體這幾個階段,整個過程會耗費一定的時間。而在 Kafka 中,主從同步會比 Redis 更加耗時,它需要經歷網路→主節點記憶體→主節點磁碟→網路→從節 點記憶體→從節點磁碟這幾個階段。對延時敏感的應用而言,主寫從讀的功能並不太適用。

Kafka中是怎麼體現訊息順序性的?

  • kafka每個partition中的訊息在寫入時都是有序的,消費時,每個partition只能被每一個group中的一個消費者消費,保證了消費時也是有序的。
  • 整個topic不保證有序。如果為了保證topic整個有序,那麼將partition調整為1.

 

 

寄語:要偷偷的努力,希望自己也能成為別人的夢想。

相關文章