一,kafka簡介
Kafka 是一種分布式的,基于發布 / 訂閱的訊息系統,主要設計目標如下:
- 以時間復雜度為 O(1) 的方式提供訊息持久化能力,即使對 TB 級以上資料也能保證常數時間復雜度的訪問性能,
- 高吞吐率,即使在非常廉價的商用機器上也能做到單機支持每秒 100K 條以上訊息的傳輸,
- 支持 Kafka Server 間的訊息磁區,及分布式消費,同時保證每個 Partition 內的訊息順序傳輸,
- 同時支持離線資料處理和實時資料處理,
- Scale out:支持在線水平擴展,
kafka的使用
- 異步通信:很多時候,用戶不想也不需要立即處理訊息,訊息佇列提供了異步處理機制,允許用戶把一個訊息放入佇列,但并不立即處理它,想向佇列中放入多少訊息就放多少,然后在需要的時候再去處理它們,
- 解耦:在專案啟動之初來預測將來專案會碰到什么需求,是極其困難的,訊息系統在處理程序中間插入了一個隱含的、基于資料的介面層,兩邊的處理程序都要實作這一介面,這允許你獨立的擴展或修改兩邊的處理程序,只要確保它們遵守同樣的介面約束,
- 削峰:在訪問量劇增的情況下,應用仍然需要繼續發揮作用,但是這樣的突發流量并不常見;如果為以能處理這類峰值訪問為標準來投入資源隨時待命無疑是巨大的浪費,使用訊息佇列能夠使關鍵組件頂住突發的訪問壓力,而不會因為突發的超負荷的請求而完全崩潰,
- 順序保證:在大多使用場景下,資料處理的順序都很重要,大部分訊息佇列本來就是排序的,并且能保證資料會按照特定的順序來處理,Kafka 保證一個 Partition 內的訊息的有序性,
二,kafka架構

- Broker:Kafka 集群包含一個或多個服務器,這種服務器被稱為 broker,
- Topic:每條發布到 Kafka 集群的訊息都有一個類別,這個類別被稱為 Topic,(物理上不同 Topic 的訊息分開存盤,邏輯上一個 Topic 的訊息雖然保存于一個或多個 broker 上但用戶只需指定訊息的 Topic 即可生產或消費資料而不必關心資料存于何處),
- Partition:物理上的概念,每個 Topic 包含一個或多個 Partition,
- Producer:負責發布訊息到 Kafka broker,
- Consumer:訊息消費者,向 Kafka broker 讀取訊息的客戶端,
- Consumer Group:每個 Consumer 屬于一個特定的 Consumer Group(可為每個 Consumer 指定 group name,若不指定 group name 則屬于默認的 group),
如上圖所示,一個典型的 Kafka 集群中包含若干 Producer,若干 broker(Kafka 支持水平擴展,一般 broker 數量越多,集群吞吐率越高),若干 Consumer Group,以及一個Zookeeper集群,
Kafka 通過 Zookeeper 管理集群配置,選舉 leader,以及在 Consumer Group 發生變化時進行 rebalance,
Producer 使用 push 將訊息發布到 broker,Consumer 使用 pull 模式從 broker 訂閱并消費訊息,
三,Topic and Partition
Kafka 中的訊息以Topic為單位進行歸類,生產者負責將訊息發送到特定的Topic(發送到 Kafka 集群中的每一條訊息都要指定一個Topic),而消費者負責訂閱Topic并進行消費,
Topic是一個邏輯上的概念,它可以細分為多個Partition,一個Partition只屬于單個Topic,同一Topic下的不同Partition包含的訊息是不同的,Partition在存盤層面可以看作一個可追加的日志(Log)檔案,訊息在被追加到磁區日志檔案的時候都會分配一個特定的偏移量(offset),
offset 是訊息在Partition中的唯一標識,Kafka 通過它來保證訊息在磁區內的順序性,不過 offset 并不跨越磁區,也就是說,Kafka 保證的是磁區有序而不是主題有序,

如上圖所示,Topic 中有4個磁區,訊息被順序追加到每個磁區日志檔案的尾部,Kafka 中的磁區可以分布在不同的服務器(broker)上,也就是說,一個 Topic 可以橫跨多個 broker,以此來提供比單個 broker 更強大的性能,
每一條訊息被發送到 broker 之前,會根據磁區規則選擇存盤到哪個具體的磁區,如果磁區規則設定得合理,所有的訊息都可以均勻地分配到不同的磁區中,如果一個主題只對應一個檔案,那么這個檔案所在的機器I/O將會成為這個主題的性能瓶頸,而磁區解決了這個問題,在創建主題的時候可以通過指定的引數來設定磁區的個數,當然也可以在主題創建完成之后去修改磁區的數量,通過增加磁區的數量可以實作水平擴展,
Kafka 為磁區引入了多副本(Replica)機制,通過增加副本數量可以提升容災能力,
同一磁區的不同副本中保存的是相同的訊息(在同一時刻,副本之間并非完全一樣),副本之間是“一主多從”的關系,其中 leader 副本負責處理讀寫請求,follower 副本只負責與 leader 副本的訊息同步,副本處于不同的 broker 中,當 leader 副本出現故障時,從 follower 副本中重新選舉新的 leader 副本對外提供服務,Kafka 通過多副本機制實作了故障的自動轉移,當 Kafka 集群中某個 broker 失效時仍然能保證服務可用,
四,producer
Producer 發送訊息到 broker 時,會根據 Paritition 機制選擇將其存盤到哪一個 Partition,如果 Partition 機制設定合理,所有訊息可以均勻分布到不同的 Partition 里,這樣就實作了負載均衡,如果一個 Topic 對應一個檔案,那這個檔案所在的機器 I/O 將會成為這個 Topic 的性能瓶頸,而有了 Partition 后,不同的訊息可以并行寫入不同 broker 的不同 Partition 里,極大的提高了吞吐率,
在發送一條訊息時,可以指定這條訊息的 key,Producer 根據這個 key 和 Partition 機制來判斷應該將這條訊息發送到哪個 Parition,
producer的ack機制
Kafka的Ack機制指producer的訊息發送確認機制,其影響kafka集群的吞吐量和訊息可靠性,
- Ack=0,相當于異步發送,意味著producer不等待broker同步完成,訊息發送完畢繼續發送下一批資訊,提供了最低延遲,但持久性最弱,當服務器發生故障時很可能發生資料丟失,如果leader死亡,producer繼續發送訊息,broker接收不到資料就會造成資料丟失,
- Ack=1,producer要等待leader成功收到訊息并確認,才發送下一條message,提供較低的延遲性以及較好的持久性,但是如果partition下的leader死亡,而follower尚未復制資料,資料就會丟失,
- Ack=-1,leader收到所有訊息,且follower同步完資料,才發送下一條資料,延遲性最差,持久性最好(即可靠性最好),
以上三種引數設定性能遞減,可靠性遞增,
Ack默認值為1,此時吞吐量與可靠性折中,實際生產中可以根據實際需求進行調整,
五,consumer
1,consumer group
同一 Topic 的一條訊息只能被同一個 Consumer Group 內的一個 Consumer 消費,但多個 Consumer Group 可同時消費這一訊息,
這是 Kafka 用來實作一個 Topic 訊息的廣播(發給所有的 Consumer)和單播(發給某一個 Consumer)的手段,一個 Topic 可以對應多個 Consumer Group,如果需要實作廣播,只要每個 Consumer 有一個獨立的 Group 就可以了,要實作單播只要所有的 Consumer 在同一個 Group 里,用 Consumer Group 還可以將 Consumer 進行自由的分組而不需要多次發送訊息到不同的 Topic,
2,pull and push
作為一個訊息系統,Kafka 遵循了傳統的方式,選擇由 Producer 向 broker push 訊息并由 Consumer 從 broker pull 訊息,
push 模式很難適應消費速率不同的消費者,因為訊息發送速率是由 broker 決定的,push 模式的目標是盡可能以最快速度傳遞訊息,但是這樣很容易造成 Consumer 來不及處理訊息,典型的表現就是拒絕服務以及網路擁塞,而 pull 模式則可以根據 Consumer 的消費能力以適當的速率消費訊息,
對于 Kafka 而言,pull 模式更合適,pull 模式可簡化 broker 的設計,Consumer 可自主控制消費訊息的速率,同時 Consumer 可以自己控制消費方式——即可批量消費也可逐條消費,同時還能選擇不同的提交方式從而實作不同的傳輸語意,
六,訊息存盤結構
如果磁區規則設定得合理,那么所有的訊息可以均勻地分布到不同的磁區中,這樣就可以實作水平擴展,不考慮多副本的情況,一個磁區對應一個日志(Log),為了防止 Log 過大,Kafka 又引入了日志分段(LogSegment)的概念,將 Log 切分為多個 LogSegment,相當于一個巨型檔案被平均分配為多個相對較小的檔案,這樣也便于訊息的維護和清理,
事實上,Log 和 LogSegment 也不是純粹物理意義上的概念,Log 在物理上只以檔案夾的形式存盤,而每個 LogSegment 對應于磁盤上的一個日志檔案和兩個索引檔案,以及可能的其他檔案(比如以“.txnindex”為后綴的事務索引檔案),下圖描繪了主題、磁區、副本、Log 以及 LogSegment 之間的關系,

每一個topic-paration對應一個檔案夾,舉個例子:
kafka-topics --create --zookeeper localhost:2181 --replication-factor 1 --partitions 4 --topic topic-bobo
創建"topic-bobo"的主題,此主題中具有4個磁區,那么在實際物理存盤上表現為“topic-bobo-0”、“topic-bobo-1”、“topic-bobo-2”、“topic-bobo-3”這4個檔案夾:

向 Log 中追加訊息時是順序寫入的,只有最后一個 LogSegment 才能執行寫入操作,在此之前所有的 LogSegment 都不能寫入資料,為了方便描述,我們將最后一個 LogSegment 稱為“activeSegment”,即表示當前活躍的日志分段,隨著訊息的不斷寫入,當 activeSegment 滿足一定的條件時,就需要創建新的 activeSegment,之后追加的訊息將寫入新的 activeSegment,

為了便于訊息的檢索,每個 LogSegment 中的日志檔案(以“.log”為檔案后綴)都有對應的兩個索引檔案:偏移量索引檔案(以“.index”為檔案后綴)和時間戳索引檔案(以“.timeindex”為檔案后綴),每個 LogSegment 都有一個基準偏移量 baseOffset,用來表示當前 LogSegment 中第一條訊息的 offset,偏移量是一個64位的長整型數,日志檔案和兩個索引檔案都是根據基準偏移量(baseOffset)命名的,名稱固定為20位數字,沒有達到的位數則用0填充,比如第一個 LogSegment 的基準偏移量為0,對應的日志檔案為00000000000000000000.log,
注意每個 LogSegment 中不只包含“.log”、“.index”、“.timeindex”這3種檔案,還可能包含“.deleted”、“.cleaned”、“.swap”等臨時檔案,以及可能的“.snapshot”、“.txnindex”、“leader-epoch-checkpoint”等檔案,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/357056.html
標籤:其他
