天天看點

Kafka實戰(二)-Kafka消息模型核心概念(下)6 RecordConsumerGroup - 消費組CoordinatorKafka的三層消息架構8 總結9 為什麼Kafka不像MySQL允許追随者副本對外提供讀服務?

6 Record

每條記錄都有key、value、 timestamp三個資訊

Kafka實戰(二)-Kafka消息模型核心概念(下)6 RecordConsumerGroup - 消費組CoordinatorKafka的三層消息架構8 總結9 為什麼Kafka不像MySQL允許追随者副本對外提供讀服務?

分區id+offset才可确定資料位置

分區内才是有序的!

ConsumerGroup - 消費組

每個Consumer屬于一個特定的Consumer Group (可為每個Consumer 指定 group name, 若不指定 group name則屬于預設的group)

  • 消費者可使用相同的

    group.id

    加入一個組
  • 每個Consumer執行個體屬于一個ConsumerGroup
  • 組的最大并行度是組中的消費者數量 ← 沒有partition
  • Kafka将topic的partition配置設定給組中的消費者,以便每個分區僅由組中的一個消費者使用
  • Kafka保證消息隻能由該組中的單個消費者讀取。消費者可按存儲在日志中的順序檢視消息
  • 每個ConsumerGroup都有一個Coordinator(協調者),負責配置設定Consumer和Partition的對應關系,當Partition或是Consumer發生變更時,會觸發reblance(重新配置設定),重新配置設定Consumer與Partition的對應關系

Coordinator

Consumer維護與Coordinator之間的心跳,這樣Coordinator就能感覺到Consumer的狀态,在Consumer故障的時候及時觸發rebalance。

Kafka的三層消息架構

  • 第一層是主題層,每個主題可以配置M個分區,而每個分區又可以配置N個副本
  • 第二層是分區層,每個分區的N個副本中隻能有一個充當上司者角色,對外提供服務;其他N-1個副本是追随者副本,隻是提供資料備援之用
  • 第三層是消息層,分區中包含若幹條消息,每條消息的位移從0開始,依次遞增

最後,用戶端程式隻能與分區的上司者副本進行互動。

講完了消息層次,來說說Kafka Broker是如何持久化資料的。總的來說,Kafka使用消息日志(Log)來儲存資料,一個日志就是磁盤上一個隻能追加寫(Append-only)消息的實體檔案。因為隻能追加寫入,故避免了緩慢的随機I/O操作,改為性能較好的順序I/O寫操作,這也是實作Kafka高吞吐量特性的一個重要手段。不過如果你不停地向一個日志寫入消息,最終也會耗盡所有的磁盤空間,是以Kafka必然要定期地删除消息以回收磁盤。怎麼删除呢?簡單來說就是通過日志段(Log Segment)機制。在Kafka底層,一個日志又近一步細分成多個日志段,消息被追加寫到目前最新的日志段中,當寫滿了一個日志段後,Kafka會自動切分出一個新的日志段,并将老的日志段封存起來。Kafka在背景還有定時任務會定期地檢查老的日志段是否能夠被删除,進而實作回收磁盤空間的目的。

這裡再重點說說消費者。

點對點模型(Peer to Peer,P2P)和釋出訂閱模型。這裡面的點對點指的是同一條消息隻能被下遊的一個消費者消費,其他消費者則不能染指。在Kafka中實作這種P2P模型的方法就是引入了消費者組(Consumer Group)。所謂的消費者組,指的是多個消費者執行個體共同組成一個組來消費一組主題。這組主題中的每個分區都隻會被組内的一個消費者執行個體消費,其他消費者執行個體不能消費它。為什麼要引入消費者組呢?主要是為了提升消費者端的吞吐量。多個消費者執行個體同時消費,加速整個消費端的吞吐量(TPS)。我會在專欄的後面詳細介紹消費者組機制,是以現在你隻需要了解消費者組是做什麼的即可。另外這裡的消費者執行個體可以是運作消費者應用的程序,也可以是一個線程,它們都稱為一個消費者執行個體(Consumer Instance)。

消費者組裡面的所有消費者執行個體不僅“瓜分”訂閱主題的資料,而且更酷的是它們還能彼此協助。假設組内某個執行個體挂掉了,Kafka能夠自動檢測到,然後把這個Failed執行個體之前負責的分區轉移給其他活着的消費者。這個過程就是Kafka中大名鼎鼎的“重平衡”(Rebalance)。嗯,其實既是大名鼎鼎,也是臭名昭著,因為由重平衡引發的消費者問題比比皆是。事實上,目前很多重平衡的Bug社群都無力解決。

每個消費者在消費消息的過程中必然需要有個字段記錄它目前消費到了分區的哪個位置上,這個字段就是消費者位移(Consumer Offset)。注意,這和上面所說的位移完全不是一個概念。上面的“位移”表征的是分區内的消息位置,它是不變的,即一旦消息被成功寫入到一個分區上,它的位移值就是固定的了。而消費者位移則不同,它可能是随時變化的,畢竟它是消費者消費進度的訓示器嘛。另外每個消費者有着自己的消費者位移,是以一定要區分這兩類位移的差別。我個人把消息在分區中的位移稱為分區位移,而把消費者端的位移稱為消費者位移。

8 總結

消息:Record。Kafka是消息引擎嘛,這裡的消息就是指Kafka處理的主要對象。

主題:Topic。主題是承載消息的邏輯容器,在實際使用中多用來區分具體的業務。

分區:Partition。一個有序不變的消息序列。每個主題下可以有多個分區。

消息位移:Offset。表示分區中每條消息的位置資訊,是一個單調遞增且不變的值。

副本:Replica。Kafka中同一條消息能夠被拷貝到多個地方以提供資料備援,這些地方就是所謂的副本。副本還分為上司者副本和追随者副本,各自有不同的角色劃分。副本是在分區層級下的,即每個分區可配置多個副本實作高可用。

生産者:Producer。向主題釋出新消息的應用程式。

消費者:Consumer。從主題訂閱新消息的應用程式。

消費者位移:Consumer Offset。表征消費者消費進度,每個消費者都有自己的消費者位移。

消費者組:Consumer Group。多個消費者執行個體共同組成的一個組,同時消費多個分區以實作高吞吐。

重平衡:Rebalance。消費者組内某個消費者執行個體挂掉後,其他消費者執行個體自動重新配置設定訂閱主題分區的過程。Rebalance是Kafka消費者端實作高可用的重要手段。

Kafka實戰(二)-Kafka消息模型核心概念(下)6 RecordConsumerGroup - 消費組CoordinatorKafka的三層消息架構8 總結9 為什麼Kafka不像MySQL允許追随者副本對外提供讀服務?

9 為什麼Kafka不像MySQL允許追随者副本對外提供讀服務?

不從follower讀幾個原因:

  1. kafka的分區已經讓讀是從多個broker讀進而負載均衡,不是MySQL的主從,壓力都在主上
  2. kafka儲存的資料和資料庫的性質有實質的差別就是資料具有消費的概念,是流資料,kafka是消息隊列,是以消費需要位移,而資料庫是實體資料不存在這個概念,如果從kafka的follower讀,消費端offset控制更複雜
  3. 生産者來說,kafka可以通過配置來控制是否等待follower對消息确認的,如果從上面讀,也需要所有的follower都确認了才可以回複生産者,造成性能下降,如果follower出問題了也不好處理

首先明确一下:主從分離與否沒有絕對的優劣,它僅僅是一種架構設計,各自有适用的場景。

Redis和MySQL都支援主從讀寫分離,這和它們的使用場景有關。對于那種讀操作很多而寫操作相對不頻繁的負載類型而言,采用讀寫分離是非常不錯的方案——我們可以添加很多follower橫向擴充,提升讀操作性能。反觀Kafka,它的主要場景還是在消息引擎而不是以資料存儲的方式對外提供讀服務,通常涉及頻繁地生産消息和消費消息,這不屬于典型的讀多寫少場景,是以讀寫分離方案在這個場景下并不太适合。

Kafka副本機制使用的是異步消息拉取,是以存在leader和follower之間的不一緻性。如果要采用讀寫分離,必然要處理副本lag引入的一緻性問題,比如如何實作read-your-writes、如何保證單調讀(monotonic reads)以及處理消息因果順序颠倒的問題。相反地,如果不采用讀寫分離,所有用戶端讀寫請求都隻在Leader上處理也就沒有這些問題了——當然最後全局消息順序颠倒的問題在Kafka中依然存在,常見的解決辦法是使用單分區,其他的方案還有version vector,但是目前Kafka沒有提供。最後、社群正在考慮引入适度的讀寫分離方案,比如允許某些指定的follower副本(主要是為了考慮地理相近性)可以對外提供讀服務。當然目前這個方案還在讨論中。

Kafka的資料會儲存到leader副本的log檔案中并寫入磁盤,随後follower副本會對資料進行同步。

參考