kafka-一些我在學習中的理解

yoylee_web發表於2019-01-22

元件結構

  • 定位:流式處理平臺
  • 作用:訊息中介軟體、儲存系統、實時流處理
  • kafka組件:消費者、生產者、topic、broker、streams、connecter
  • 一個典型的Kafka叢集中包含若干Producer(可以是web前端產生的Page View,或者是伺服器日誌,系統CPU、Memory等),若干broker(Kafka支援水平擴充套件,一般broker數量越多,叢集吞吐率越高),若干Consumer Group,以及一個Zookeeper叢集。Kafka通過Zookeeper管理叢集配置,選舉leader,以及在Consumer Group發生變化時進行rebalance。Producer使用push模式將訊息釋出到broker,Consumer使用pull模式從broker訂閱並消費訊息。
  • broker : 經紀人,相當於一個kafka伺服器,管理該伺服器中的所有不同topic 的分割槽
  • topic:相當於一個訊息佇列,可以將topic進行分割槽,所有分割槽組合起來為一個topic的所有訊息。分割槽可以分佈在不同的伺服器也可以分佈在同一伺服器。
  • 分割槽(partition):topic的物理上的分割槽,每個partition是一個有序的佇列,每個分割槽又會有leader 分割槽 和 follower 分割槽,所有的消費請求全部由leader處理,follower被動備份leader中的資料分佈在kafka叢集中不同的伺服器中,當leader掛了之後,在follower中選擇一個作為leader提供服務。partition由多個 segment檔案組成(log檔案)。消費者可以指定分割槽,生產者也可以指定分割槽,這種設計風格,讓消費者可以對敏感性的訊息進行區域性處理。
  • offset:partition中的每個訊息都有一個連續的序列號叫做offset,用於partition唯一標識一條訊息.
  • segment文件:partition物理上由segment檔案組成,
  • 消費模式:點對點模式(佇列模式,一個消費者對應一個訊息佇列,每個消費佇列也只能對應一個),釋出訂閱模式(topic 與 消費者為多多對應關係 )
  • kafka中的消費模式實現,kafka為這兩種的消費模型提供了統一的消費者抽象模型:消費者組
    • 點對點模式:消費組的概念,假設一個topic被消費,所有的消費這個topic的消費者都在一個消費組中,那麼就可以看作是點對點模式了
    • 釋出訂閱模式:一個topic被消費,所有消費這個topic的消費者不再一個組中,多個組消費同一個topic 那麼就是該模型
  • 消費者組:每個消費者都有消費者組標識,標識自己屬於哪一個消費者組,消費者組去訂閱topic,topic的資料被消費者組的消費者均分,一個分割槽對應一個消費者。如果一個消費者組有3個例項,一個topic有2個分割槽,則會有一個消費者永遠獲取不到資料。 一個消費者組只能對應一個topic,組中的每個消費者對應topic的一個分割槽,在初始化階段,消費者隨機選擇分割槽(也可以手動分配不過較複雜)。一個topic可以被多個消費者組消費。topic和消費者組是一對多的關係。所以,注意相同的消費者組中不能有比分割槽更多的消費者,否則多出的消費者一直處於空等待,不會收到訊息。
  • streams:負責處理訊息在kafka中的流轉,資訊流的處理直接使用producer和consumer API進行簡單的處理。對於複雜的轉換,Kafka提供了更強大的Streams API。可構建聚合計算或連線流到一起的複雜應用程式。完成實時流處理。 Sterams API在Kafka中的核心:使用producer和consumer API作為輸入,利用Kafka做狀態儲存,使用相同的組機制在stream處理器例項之間進行容錯保障。
  • connecter:負責將kafka連線到不同的資料儲存系統,比如mysql資料庫,txt檔案等
  • 訊息順序性:kafka只能保證一個topic中一個分割槽的訊息順序性,一個topic中的多個分割槽無法保證順序一致性,要想保證一個topic的順序一致性只能將topic 設定為一個分割槽。
  • 複製因子: 是相對於topic的分割槽來定義的,如果一個topic的複製因子設定為N,分割槽的leader+follower的數量為N,則該topic允許N-1伺服器當機而不丟失任何已經提交(committed)的訊息。

儲存結構

  • 檔案系統具體看另一篇筆記
  • kafka檔案系統:指的是partition中segment檔案(log、index)的儲存結構
  • kafka使用檔案系統並依賴頁快取(page cache)來保證在當機快取保持可用、儲存大量訊息的情況下的常數複雜度獲取訊息資料。
  • 每個topic的partition是一個大資料夾,裡面有許多segment資料夾,
  • 頁快取是將磁碟中的對應的資料頁載入到預先分配好的記憶體中等待程式使用,具有預讀和替換的功能。
  • 當記憶體空間耗盡時,可以將訊息資料 flush到磁碟中,而不必要儘可能的把資料維持在記憶體中。
  • kafka的儲存是以頁快取為中心進行設計的
  • 設計儲存結構的主要目的:提高磁碟利用率和訊息處理效能。
  • 事實上,kafka無需任何效能損失既可以訪問幾乎無限制的磁碟空間,這意味著可以提供一般訊息傳遞系統無法提供的特性。 例如,在Kafka中,訊息被消費後不是立馬被刪除,我們可以保留訊息相對較長的時間(例如一個星期)。 這將為消費者帶來很大的靈活性
  • 如何保證常數時間複雜度獲取訊息
    • 選擇消費的topic
    • 負載均衡找到對應的partition,非初次則找到該消費執行緒對應的partition
    • 根據記錄的offset二分法查詢partition對應segment檔案(log file and index file),並將其讀入到頁快取中,採用零拷貝的方式將所需資料傳送到網路卡緩衝區 O(1)
    • 查詢對應index檔案,在index檔案中找到對應的實體地址,找到訊息

高吞吐量

Kafka 高吞吐依賴的主要有三點:

  1. micro-batch處理方式,也就是當前Spark Streaming(實時流處理框架)所使用的模式,不是一條條的傳送訊息,而是一小批一小批的處理。通過微乎其微的延時消耗換取吞吐量幾百倍的提升。這種方式也更讓Kafka像是一個流處理框架,並且現在Kafka也已經被用於一些流處理的場景了。 Kafka通過遞迴訊息集來支援這一點。 一批訊息可以一起壓縮並以此形式傳送到伺服器。 這批訊息將以壓縮形式寫入,並將在日誌中保持壓縮,並且只能由消費者解壓縮。Kafka支援GZIP和Snappy壓縮協議
  2. 使用追加寫的方式(順序寫):這一點至關重要,我們知道在普通的機械硬碟中隨機讀寫和順序讀寫速度差異完全不是一個數量級的,SSD順序讀、機械硬碟順序讀的速度甚至比記憶體的隨機讀速度還要高。熟知作業系統的話,都很清楚磁碟讀寫操作的主要時間消耗是因為機械操作的循道等消耗。
  3. Linux中的sendfile的零拷貝加持,所謂的零拷貝其實就是原本一份資料的IO是需要經過多次copy操作&核心態與使用者態的上下文切換,讀核心態快取到應用程式快取再從應用程式快取到Socket快取完成具體的IO操作,而sendFile系統呼叫零拷貝就是避免了上下文切換帶來的copy操作,同時利用直接儲存器訪問技術(DMA)執行IO操作,避免了核心緩衝區之前的資料拷貝操作。上升到上層的語言操作,就是使用的Java中的FileChannel.transferTo方法進行實現的。(Kafka 1版本使用的是Scala,2版本開始就是使用Java 了這兩者都是在JVM上執行的,本質.class 檔案解析執行階段其實是一致的)

非零拷貝:使用者程式獲取資料並且將資料通過網路傳送到呼叫者方的過程需要四次資料拷貝,兩次系統呼叫,兩次使用者態核心態上下文切換: 1:作業系統通過DMA將資料從磁碟拷貝到核心空間的頁快取中 2:通過系統呼叫將頁快取的資料拷貝到使用者程式的空間快取中 3:使用者程式要通過網路將資料傳送到目標方,則需要通過系統呼叫將使用者程式的快取資料傳送到核心空間中的socket快取中 4:核心空間中作業系統通過DMA將socket 快取中的資料傳送到網路卡緩衝區中

零拷貝(zero-copy):kafka使用sendfile()方式,只有消費(pull)訊息時才會適用零拷貝,push訊息時可能會對訊息進行一些處理,這必須要將資料拷貝到使用者態進行處理。 資料傳送只發生的核心空間,沒有上下文切換,允許作業系統直接將頁快取中的資料傳送到網路中,過程為: 1:作業系統通過DMA將資料從磁碟拷貝到核心空間的頁快取中 2:將帶有檔案位置和長度資訊的緩衝區描述符新增socket緩衝區,這一步不復制頁快取中的資料 3:作業系統通過描述符資訊直接將頁快取中的資料傳送到網路卡緩衝區 零拷貝技術有多種,每一種有其適用場景和侷限性,比如上述kafka適用的零拷貝技術就是使用的sendfile,並且需要硬體已經驅動程式支援(比如上述的第三步就需要硬體和驅動程式來支援了),其他的還有mmap、splice等具體請看:linux中零拷貝技術筆記

  1. 標準化二進位制資料格式,在consumer、products、broker中間的流轉的訊息資料塊採用同一種二進位制格式,減少格式轉換,提高吞吐量
  2. 資料壓縮傳輸,kafka支援多種資料壓縮格式。

負載均衡&故障轉移

  • 負載均衡

    • kafka是一種分散式的訊息系統,要做負載均衡,也就是要做到均勻分配到所有參與工作的伺服器。這裡Kafka使用的是分割槽只能領導者選舉,也就是來均勻的選擇分割槽,保證各個分割槽收到的請求訊息都是大致均勻的。
    • Kafka中有一個叫做partition的概念,也就是分割槽選擇器,預設使用的是murmur2Hash 演算法計算訊息key值的hash值,然後對於總分割槽數進行求模得到對應的目標分割槽號,murmur2Hash是一種比較先進的Hash演算法,並且在有規律的輸入時也能保證分佈較為均勻,使用這個演算法的還有redis(當字典被用作資料庫的底層實現或者hash鍵的底層實現時,來計算鍵的雜湊值)、nginx、Hadoop。除此之外,使用者可以自定義對應的
  • 故障轉移

    • 常見的故障轉移實現策略的關鍵通常是故障發現,Kafka依賴的是zk的 心跳檢測機制,當一臺Kafka伺服器啟動後將會話註冊到Zookeeper中,
    • zk不停的對節點進行心跳檢測,故障發生時與Zookeeper的會話無法維持導致連線超時從而發現故障,此時請求就不再打到這臺機器,並且選舉出一臺新的Kafka伺服器來替代這臺故障的Kafka伺服器。 另外一種情況,如果節點為一個slave,那麼不能落後leader太多。這也會導致將該節點判定為故障,這裡的落後太多可能兩個原因導致一個是網路太慢導致複製太慢從而落後太多,另外一個就是卡主好多次leader 向slave複製都沒有作用。 落後是通過replica.lag.max.messages配置控制,卡住是通過replica.lag.time.max.ms配置控制的。

伸縮性

如何輕易的向kafka叢集中增加計算資源,並且保證計算資源儘可能的線形疊加。在分散式系統中伸縮性一直是一個較大的問題,因為僅僅是增加機器資源通常會因為一些隱藏的單點瓶頸導致無法線線形擴容,比如說最大的因素就是服務狀態的儲存。“狀態的處理”比如一致性,需要維持狀態的一致性就需要浪費大量的cpu資源,所以為了降低這種消耗,Kafka將絕大部分的狀態儲存及維持相關的交給kafka controller(被zk選舉出來的broker) 統一管理。Kafka 伺服器內部僅維持少量暫時需要的狀態。

每一條訊息被髮送到Kafka中,其會根據一定的規則選擇被儲存到哪一個partition中。如果規則設定的合理,所有的訊息可以均勻分佈到不同的partition裡,這樣就實現了水平擴充套件

消費與生產訊息

  • 消費者消費訊息所採用的方式:pull或者push?
    • 這裡的pull和push都是相對於消費者來說的
    • 第一種是伺服器push給消費者,優點是一點服務端資料有變消費者可以立馬感知到變化,缺點是無法預估消費者消費能力可能造成訊息堆積
    • 第二種消費者主動pull伺服器,優點可以適應消費者自身的消費速度還可以消費者指定消費訊息量批處理傳輸訊息,缺點是如果伺服器沒有資料,則消費者會一直輪詢伺服器造成計算機資源浪費,優化的手段可以採用long poll長輪詢。
    • 在kafka中使用的是pull加long poll的方式
  • 如何保證消費者與broker消費的訊息達成一致?
    • kafka也無法達成完全一致,但是對一致性做了輕量化處理,其處理方式為,每個topic的partition完全有序,每一個partition只對應消費組中的一個消費者,這樣消費者在每個分割槽中的位置只需要一個整數(offset)即可。這可以使得已經消費到哪裡位置的狀態變得特別小,每個分割槽只有一個數字,可以進行定期檢查,這樣的設計使得訊息的應答(消費者消費訊息的確認)更加輕量。
    • 這種非完全一致性可能導致訊息的重複消費,比如:消費者消費了資料,但是應答資料在網路中丟失,這就會導致offset不是最新的,導致訊息重複消費
  • kafka對於消費者和生產者預設支援的是“至少一次(at lwast once)”語義
    • 讀取訊息->處理訊息->ack到broker->修改offset
    • 只要“ack到broker”這步丟失,那麼訊息可能會重複消費,這也滿足最少一次語義。
  • broker如何保證生產者訊息不重複?
    • 在版本0.11之後,kafka提供冪等性機制,broker為每個生產者分配一個ID,並通過生產者傳送的序列號為每個訊息進行去重。即使生產者push訊息後“收到確認”在網路中丟失導致重新傳送message,在broker中也不會儲存重複的message。

如果您不同理解,請在評論出指出,共同學習!

如果感覺這篇文章對您有所幫助,請點選一下“喜歡”或者“關注”博主,您的喜歡和關注將是我前進的最大動力!

相關文章