高性能
-
消息的順序性、順序寫磁盤
-
零拷貝
-
RocketMQ內部主要是使用基于mmap實現的零拷貝,用來讀寫文件
-
減少cpu的拷貝次數和上下文切換次數,實現文件的高效讀寫操作
-
- Kafka
零拷貝
- Kafka 使用到了 mmap 和 sendfile 的方式來實現零拷貝。分別對應 Java 的 MappedByteBuffer 和 FileChannel.transferTo
順序寫磁盤
- Kafka 采用順序寫文件的方式來提高磁盤寫入性能。順序寫文件,基本減少了磁盤尋道和旋轉的次數
- 完成一次磁盤 IO,需要經過尋道、旋轉和數據傳輸三個步驟,如果在寫磁盤的時候省去尋道、旋轉可以極大地提高磁盤讀寫的性能。
- Kafka 中每個分區是一個有序的,不可變的消息序列,新的消息不斷追加到 Partition 的末尾,在 Kafka 中 Partition 只是一個邏輯概念,Kafka 將 Partition 劃分為多個 Segment,每個 Segment 對應一個物理文件,Kafka 對 segment 文件追加寫,這就是順序寫文件
頁緩存技術
- 應當使用本地磁盤作為存儲介質。Page Cache 的存在就可以提升消息的讀取速度,
批量傳輸與壓縮消息
- 生產端有兩個重要的參數:batch.size和linger.ms。這兩個參數就和 Producer 的批量發送消息有關。
網絡模型
- Kafka 自己實現了網絡模型做 RPC。底層基于 Java NIO,采用和 Netty 一樣的 Reactor 線程模型。
- Kafka 即基于 Reactor 模型實現了多路復用和處理線程池。
- Reactor 模型基于池化思想,避免為每個連接創建線程,連接完成后將業務處理交給線程池處理;基于 IO 復用模型,多個連接共用同一個阻塞對象,不用等待所有的連接。遍歷到有新數據可以處理時,操作系統會通知程序,線程跳出阻塞狀態,進行業務邏輯處理
分區并發
- Kafka 的 Topic 可以分成多個 Partition,每個 Paritition 類似于一個隊列,保證數據有序。同一個 Group 下的不同 Consumer 并發消費 Paritition,分區實際上是調優 Kafka 并行度的最小單元,因此,可以說,每增加一個 Paritition 就增加了一個消費并發。
高效的文件數據結構
- 每個 Topic 又可以分為一個或多個分區。每個分區各自存在一個記錄消息數據的日志文件。Kafka 每個分區日志在物理上實際按大小被分成多個 Segment。
- segment file 組成:由 2 大部分組成,分別為 index file 和 data file,此 2 個文件一一對應,成對出現,
- index 采用稀疏索引,這樣每個 index 文件大小有限,Kafka 采用mmap的方式,直接將 index 文件映射到內存,這樣對 index 的操作就不需要操作磁盤 IO
- 分段和索引的策略:利用偏移量和時間索引文件實現快速消息查找
高可用
-
Kafka
- Kafka 從 0.8 版本開始提供了高可用機制,可保障一個或多個 Broker 宕機后,其他 Broker 能繼續提供服務
分區副本、備份機制
同一個 Partition 存在多個消息副本,每個 Partition 的副本通常由 1 個 Leader 及 0 個以上的 Follower 組成,
- Kafka 會盡量將所有的 Partition 以及各 Partition 的副本均勻地分配到整個集群的各個 Broker 上
- 多副本機制
- 分區(Partition)引入了多副本(Replica)機制。
- 多分區、多副本機制好處呢?
- 1. Kafka 通過給特定 Topic 指定多個 Partition分區, 而各個 Partition 可以分布在不同的 Broker 上, 這樣便能提供比較好的并發能力(負載均衡)。
- 2. Partition 可以指定對應的 Replica 數, 這也極大地提高了消息存儲的安全性, 提高了容災能力,不過也相應的增加了所需要的存儲空間。
ACK 機制
-
-
-
- 生產者發送消息中包含 acks 字段,該字段代表 Leader 應答生產者前 Leader 收到的應答數
- 「acks=0」
- 生產者無需等待服務端的任何確認,因此 acks=0 不能保證服務端已收到消息
- 「acks=1」默認值
- 只要 Partition Leader 接收到消息而且寫入本地磁盤了,就認為成功了,不管其他的 Follower 有沒有同步
- 「acks=all or -1」
- 服務端會等所有的 follower 的副本受到數據后才會收到 leader 發出的 ack,這樣數據不會丟失
- Broker 有個配置項min.insync.replicas(默認值為 1)代表了正常寫入生產者數據所需要的最少 ISR 個數
- 發送的 acks=1 和 0 消息會出現丟失情況,為了不丟失消息可配置生產者acks=all & min.insync.replicas >= 2
-
-
ISR 機制
-
-
-
- ISR 中的副本都是與 Leader 同步的副本,不在 ISR 中的Follower副本就被認為是沒有資格的
- Follower 周期性地向 Leader 發送 FetchRequest 請求,發送時間間隔配置在replica.fetch.wait.max.ms中,默認值為 500
- 每個分區的 Leader 負責維護 ISR 列表并將 ISR 的變更同步至 ZooKeeper,被移出 ISR 的 Follower 會繼續向 Leader 發 FetchRequest 請求,試圖再次跟上 Leader 重新進入 ISR
- ISR 中所有副本都跟上了 Leader,通常只有 ISR 里的成員才可能被選為 Leader
-
-
主從同步
-
-
-
- 1、Follower副本通過發送Fetch請求來同步Leader副本上的數據。
- LEO(Log End Offset)
- 對于Leader副本和每個Follower副本來說,它們都有各自的LEO
- LEO是下一個要寫入的消息的偏移量
- HW(High Watermark)
- HW是分區中所有副本的已提交消息的最大偏移量。是分區中所有ISR(In-Sync Replicas)副本的LEO中的最小值
- 只要分區的Leader副本和至少一個Follower副本保持同步,消費者就能看到所有已提交的消息,即使Leader副本發生故障
- 確保了Kafka在分區的Leader副本發生故障時,可以從ISR中選舉出一個Follower副本作為新的Leader,
- Unclean 領導者選舉
- 當 Kafka 中unclean.leader.election.enable配置為 true(默認值為 false)且 ISR 中所有副本均宕機的情況下,
- 開啟 Unclean 領導者選舉可能會造成數據丟失,但好處是,它使得分區 Leader 副本一直存在,不至于停止對外提供服務,因此提升了高可用性,
-
-
Leader 選舉 & 故障恢復機制
-
-
-
- 「Kafka 從 0.8 版本開始引入了一套 Leader 選舉及失敗恢復機制」
- 在集群所有 Broker 中選出一個 Controller,負責各 Partition 的 Leader 選舉以及 Replica 的重新分配
- Controller
- 集群中的 Controller 也會出現故障,因此 Kafka 讓所有 Broker 都在 ZooKeeper 的 Controller 節點上注冊一個 Watcher。
- 當出現 Leader 故障后,Controller 會將 Leader/Follower 的變動通知到需要為此作出響應的 Broker。
- Kafka 使用 ZooKeeper 存儲 Broker、Topic 等狀態數據,Kafka 集群中的 Controller 和 Broker 會在 ZooKeeper 指定節點上注冊 Watcher(事件監聽器),以便在特定事件觸發時,由 ZooKeeper 將事件通知到對應 Broker
- 當 Broker 發生故障后,由 Controller 負責選舉受影響 Partition 的新 Leader 并通知到相關 Broker
-
-