Kafka 社區KIP-405中文譯文(分層存儲)

来源:https://www.cnblogs.com/xijiu/p/17974292
-Advertisement-
Play Games

嗨,大家好!歡迎來到C-Shopping,這是一場揭開科技面紗的電商之旅。我是C-Shopping開源作者“繼小鵬”,今天將為你介紹一款基於最新技術的開源電商平臺。讓我們一同探索吧! 點擊 這裡,http://shop.huanghanlian.com/,即刻踏上C-Shopping 體驗之旅! 項 ...


原文鏈接:https://cwiki.apache.org/confluence/display/KAFKA/KIP-405%3A+Kafka+Tiered+Storage

譯者:Kafka KIP-405是一篇非常優秀的多層存儲的設計稿,不過此設計稿涉及內容很多,文章量大、嚴謹、知識點諸多。我們國內還沒有對其有相對完整的譯文,面對如此上乘的文章,譯者想降低其門檻,讓國內更多的人瞭解其設計,因此花費了諸多時間精力將此文進行了全文翻譯,同時有一些可能讓人產生疑惑的技術細節,譯者也都打上了註釋,希望可以幫助更多的人。當然如果有一些Kafka基礎,且英文閱讀流暢的話,譯者還是建議去看原文

背景

Kafka是基礎數據重要的組成部分,並且已經得到用戶廣泛的認可,增長勢頭迅猛。隨著集群規模的增加,越來越多的數據將會被存儲在Kafka上,其消息的保留時長、集群的彈縮、性能以及運維等日益變得越來越重要

Kafka採用append-only的日誌追加模式,將數據存在在本地磁碟中。消息保留時長通過配置項log.retention來進行控制,既可以設置全局層面的,同時也可以設計某個topic維度的。消息保留時長能否確保數據持久化不丟失,即便是consumer短暫性宕機或不可用,當其成功重啟後,只要時間沒有超過log.retention,消息依舊能夠讀取

總的消息的存儲量,與topic/partition數量、消息存儲速率、消息保留時長相關,一個Kafka的Broker通常在本地磁碟上存儲了大量的數據,例如10TB,這種大量本地存儲的現象給Kafka的維護帶來了巨大挑戰

Kafka作為一種長期的存儲服務

Kafka的普及率越來越高,也逐漸成為了很多數據的入口。它會將數據持久化下來,因此允許用戶進行一些非實時的消費操作。很多用戶因為Kafka協議的簡單以及消費者API的廣泛採用,且允許用戶將數據保留很長一段時間,這些特性都有助於Kafka日益成為了數據的source of data(SOT)

目前,Kafka一般會配置一個較短的保留時長(例如3天),然後更老的數據可以通過數據管道拷貝至更具彈縮能力的外部存儲(例如HDFS)以便長期使用,結果就是客戶端需要建立2種機制去讀取數據,相對新的數據讀取Kafka,老數據則讀取HDFS

Kafka存儲的提高,一般是依賴增加更多的Broker節點來實現的,但是這樣同樣也會導致新增了更多的記憶體+cpu,相對比可彈縮的外部存儲來講,這樣無疑是增加了全局的開銷,並且一個很多節點的集群同樣增加了運維、部署的難度

Kafka本地存儲以及維護的複雜性

當Kafka的一個broker壞掉了,將會用一個新的broker來替代,然後這個新節點必須從其他節點上拉取舊節點的全量數據。同樣,當新添加一個broker來橫向擴展集群存儲時,集群的rebalance會為新節點分配分區,這同樣需要複製大量的數據。恢復及rebalance的耗時與kafka broker上的數據量呈正相關。許多多broker的集群(例如100個broker),節點故障是非常常見的情況,在恢復過程中消耗了大量的時間,這使得運維操作變得非常困難

減少每個broker上的存儲數據量能夠減少recovery及rebalance時間,但是這樣操作的話同樣需要減少消息的保留時長,這樣就使得Kafka可提供的消息回溯時間變得更少

Kafka上雲

本地部署的Kafka一般都會使用多個具備硬體SKU的高容量磁碟,從而最大程度提高I/O的吞吐量。而在雲上,具有類似SKU的本地磁碟,要麼不可用,要麼非常昂貴。如果Kafka能夠使用容量較小的SKU作為本地存儲,那麼它就更適合上雲

解決方案 - Kafka分層存儲

Kafka數據主要以流式方式使用尾部讀取來進行消費,提供讀取的層,一般都是操作系統的Page Cache,而不是穿透到磁碟。而舊的數據一般是為了回溯或者是因為consumer故障後重啟後讀取的,而這種情況一般不太常見。

在分層存儲方法中,Kafka集群配置有兩層存儲:本地和遠程(local and remote)。本地存儲層與當前的Kafka相同,使用Kafka Broker上的本地磁碟來存儲日誌段。而新的遠端存儲層則使用一些外部存儲,例如HDFS或者S3來實現。不同的存儲層使用不同的日誌過期時間。當開啟遠程存儲時,本地消息的保留時長將會從幾天縮短至幾小時,而遠端存儲的消息保留時長則可能會保留更長的時間,例如幾周甚至幾個月。當本地日誌段發生了滾動 (譯者:這裡所謂的滾動rolled,可以簡單理解為某個日誌段寫滿1G了,即數據已經不會再發生變化了),它可能就會被拷貝至遠端存儲,當然包含日誌段相關的索引文件。這樣即便是延遲敏感的數據也能獲得高效的消費,因為數據都是尾部讀取,且數據都會高概率命中page cache。而那些讀取歷史消息,或者對消息進行回溯的場景,很有可能數據已經不在本地存儲了,那麼它們將會去遠端存儲上讀取

此解決方案允許在Kafka集群擴容存儲時,將不再依賴於記憶體和CPU,使Kafka成為一個長期存儲的解決方案。同時也減少了每個broker上本地存儲的數據量,從而減少了集群recovery及rebalance時需要複製的數據量。broker不需要恢復遠程存儲層中的日誌段,也不存在惰性恢復,而是遠程存儲層直接提供服務。這樣,增加消息保留時長就不需要再擴展Kafka集群的broker數量了,同時消息總體的保留時長還可以更長,不用像當前很多集群部署的策略,需要啟動一個單獨的管道,將數據從Kafka拷貝至外部存儲了

Goals

通過將舊數據存儲在外部存儲(如HDFS或S3)中,實現了將Kafka的存儲擴展到了集群之外,不過Kafka的內部的協議不能有太大的變動。對於那麼沒有啟用分層存儲功能的現有用戶,Kafka各類行為及操作複雜性決不能改變

Non-Goals

  • 分層存儲不能取代ETL管道任務。現有的ETL管道繼續按原樣消費Kafka的數據,儘管Kafka有更長的消息保留時長
  • 二級存儲不適用於compact類型的topic。即便是將compact類型的topic的配置項remote.storage.enable設置為true,也不能將其類型由delete改為compact
  • 二級存儲不支持JBOD特性

變更

高層設計

RemoteLogManager (RLM) 是一個新引入的組件:

  • 處理leader變更、topic partition刪除等回調事件
  • 可插拔的存儲管理器(即RemoteStorageManager)將處理segments的copy、read、delete事件,且其需要維護遠端segments日誌段的元數據(它需要知道哪些segments存儲在了遠端)

RemoteLogManager 是一個內部組件,不會向外暴露API

RemoteStorageManager 本身是一個介面,它定義了遠端日誌段及索引的生命周期。具體細節下文還會說明,我們將提供一個簡單的RSM的實現來幫助大家更好的理解它。而諸如HDFS或者S3的實現應該放在他們產品的倉庫中,Apache Kafka自身的倉庫不會包含其具體的實現。這個設計與Kafka connnector保持一致

譯者:其實這裡本質上Kafka定義了一套多層存儲的規範。突然想起一句話:普通的軟體在編碼,上流的軟體在設計,頂級的軟體在定義規範

RemoteLogMetadataManager 本身也是個介面,它同樣定義了具有強一致語義的遠端元數據的生命周期。它的預設實現是一個kafka系統內部的topic,用戶如果需要使用其他遠程存儲介質來存儲元數據的話,需要自己去擴展它

RemoteLogManager (RLM)

RLM為leader及follower啟動了很多任務,具體解析可見下文

  • RLM Leader 職責
    • 它會不斷地檢查非active狀態的LogSegments(這些LogSegments中最大的offset需要嚴格小於LSO,才能進行拷貝),然後將這些LogSegments及索引文件(offset/time/transaction/producer-snapshot)、leader epoch均拷貝至遠端存儲層
    • 提供從遠端存儲層查詢舊數據的服務(當查詢的數據在local log存儲中沒有時)
    • 即便是local存儲已經不足(或存儲的日誌已經超時 ?這裡存疑),也要先將日誌段LogSegments拷貝至遠端後,再刪除
  • RLM Follower 職責
    • 通過訪問RemoteLogMetdataManager來獲取遠端存儲的log及index數據
    • 同時,它也會提供從遠端存儲層查詢舊數據的服務

RLM提供了一個本地的有界緩存(可能是LRU淘汰策略)來存儲遠端的索引文件,這樣可避免頻繁的訪問遠端存儲。它們存儲在log dir目錄下的remote-log-index-cache子目錄,這些索引可以像local索引一樣使用,用戶可以通過設置配置項remote.log.index.file.cache.total.size.mb來設定此緩存的上限

在早期的設計中,還包含了通過遠端存儲的API拉取LogSegments元數據的章節,(譯者:這應該是曾經討論的某次中間版本)它在HDFS接入時,看起來一切運行的很好。依賴遠端存儲來維護元數據的問題之一是:整個分層存儲是需要強一致性的,它不僅影響元數據,還影響Segments日誌段數據本身。其次也要考慮遠端存儲中存儲元數據的耗時,在S3中,frequent LIST APIs導致了巨大的開銷

譯者:主要是講為什麼要將元數據與日誌數據分開存儲的原因。這段可能讀起來有點摸不著頭腦,原因是咱們沒有參與他們之前的討論,之前的某個討論版本是想將日誌的元數據信息放入遠程存儲的,此處不用糾結

因此需要將遠端的數據本身,與元數據進行分離,其對應的管理類分別為RemoteStorageManagerRemoteLogMetadataManager

本地及遠端offset約束

以下是leader offset相關描述圖

Lx = Local log start offset Lz = Local log end offset Ly = Last stable offset(LSO)

Ry = Remote log end offset Rx = Remote log start offset

Lz >= Ly >= Lx and Ly >= Ry >= Rx

譯者:這裡不做贅述,關鍵一點是remote offset中的最大值,是需要 <= LSO的

Replica Manager

譯者:註意,ReplicaManager是獨立存在的,在沒有引入多層存儲的時候,它就在,不過以前只管理local存儲罷了。它其實是RLM的上一層

如果配置了RLM,那麼ReplicaManager將調用RLM來分配或刪除topic-partition

如果某個Broker從Leader切換為了Follower,而正在此時,RLM正在工作,它正在將某個Segment拷貝至遠端,我們這個時候不會直接將其放棄掉,而是會等它完成工作。這個操作可能會導致Segment片段的重覆,但是沒關係,在遠端存儲的這些日誌過期後,均會刪除

譯者:為什麼會導致Segment片段的重覆呢? 因為很有可能新的leader已經對同一份Segment進行了上傳

Follower Replication

Overview

目前,followers從leaders拉取消息數據,並且儘力嘗試追上leader的log-end-offset(LEO),從而將自己的狀態變為in-sync副本。如果需要,follower可能還會截斷自己的日誌從而與leader的數據保持一致

譯者:Kafka為了保證數據的高可用,make leader的過程可能會對HW以上的記錄進行截斷

而在多級存儲,follower同樣需要與leader的數據保持一致,follower僅複製leader中已經可用的本地存儲的消息。但是他們需要為遠端的Segment構建諸如「leader epoch cache」、「producer id snapshot」這些狀態,甚至有必要,它們還需要對其進行截斷

下麵這張圖對leader、follower、remote log、metadata storage 4者的關係進行了簡明的概述,具體的細節將在下文展開

  1. Leader將Segment日誌端及AuxiliaryState(含leader epoch及producer-id snapshots)拷貝至遠端存儲
  2. Leader將剛纔上傳的Segment日誌段的元數據發佈出去
  3. Follower從Leader拉取消息,並遵循一定的規範,這個規範在下文具體說明
  4. Follower等待Leader將元數據放入RemoteLogSegmentMetadataTopic後將其拉取下來
  5. Follower抓取相應的遠端存儲的元數據,並構建狀態AuxiliaryState

譯者:關於第2步,leader將元數據發佈出去,這裡需要註意的是,存儲partition元數據的介質並不一定是遠端存儲,預設實現是,kafka將其放在了一個內置的topic中,如上文提到的,如果用戶願意,可以將其擴展為一個遠程存儲

而這裡的partition元數據具體是指什麼呢?原文並沒有說明,其實就是每個Segment是存儲在了本地還是遠端,可根據這個元數據進行路由

Follower拉取消息協議細節

Leader epoch概念的引入,是為瞭解決在KIP-101及KIP-279中提到的leader切換的場景中,可能存儲日誌差異的問題。它(Leader epoch)是partition下的一個單調遞增的整數,每當leader進行了切換,那麼這個值將會累加,並且它也會存儲在消息的message batch中

Leader epoch文件存在於每個broker的每個partition中,然後所有狀態是in-sync的副本需要保證其有同樣的leader epoch歷史信息,以及相同的日誌數據

Leader epoch的作用:

  • 決定日誌截斷(KIP-101)
  • 保證副本間的一致性(KIP-279)
  • 在發生截斷後,重置消費位點(KIP-320)

在使用遠端存儲時,我們應該像使用本地存儲一樣,來處理日誌及leader epoch

目前,純本地存儲的場景,follower從leader拉取消息後,通過讀取message batch來構建AuxiliaryState狀態。

譯者:這裡需要註意,純本地存儲的case是,follower需要不斷的從leader拉取消息,而這些消息會攜帶leader epoch 信息,從而維護自己的leader-epoch-checkpoint文件,kafka本身不提供專門的API來同步此文件信息,譯者認為這樣做也是比較合理的

而在多級存儲中,follower需要讀取leader構建出來的AuxiliaryState,從而獲取起始offset及leader epoch。然後follower將會從這個起始offset開始拉取數據。這個起始offset可能是「local-log-start-offset」或「last-tiered-offset」。local-log-start-offset是本地存儲的開始offset;last-tiered-offset是已經拷貝至遠端存儲的最大offset。我們來討論下使用這兩者的利弊

last-tiered-offset

  • 用這個策略明顯的好處就是follower能否非常快的追上leader,因為follower只需要同步那些存在於leader本地存儲中,且還沒來得及放在遠端的日誌段
  • 而這樣做的一個缺點是,follower相對於leader缺少很多本地日誌段,當這個follower成為leader後,其他follower將會根據新leader的log-start-offset來截斷它們的日誌段

譯者:關於這個缺點,是kafka自身的副本同步協議中定義的,因為follower不斷地從leader拉取消息,努力跟leader保持一致,一致不僅包括offset的上端,同時也包括offset的下端

local-log-start-offset

  • 在發生leader切換時,將會保留本地日誌
  • follower追趕leader,這將會花費較長的時間,當為某個partition新增一個全新follower時,就命中了這個case

基於上述原因,我們更傾向使用「local-log-start-offset

在多層存儲中,當follower來拉取數據時,leader只會返回在本地存儲中存在的數據。那些已經存在在遠端,且本地已經沒有的日誌段,follower是不會進行拉取複製的。根據「local-log-start-offset」機制,如果有必要的話,follower可能會截斷自己的日誌

譯者:同上文,follower是會根據leader的local-log-start-offset來截斷自己日誌段的

當一個follower從leader拉取一個leader的本地存儲已經不存在的offset時,leader將會發送一個錯誤碼OFFSET_MOVED_TO_TIERED_STORAGE,然後follower將會重新從leader獲取「local-log-start-offset」及「leader eopch」。follower收到leader的local-log-start-offset後,需要基於這個offset構建遠端日誌段的AuxiliaryState,「譯者:此處註意,在純local存儲的模式下,follower是通過拉取leader的全量日誌,並且在這個拉取過程中,逐步構建並維護leader-epoch-checkpoint文件的。而在多層存儲的環境中,因為follower不再需要從leader處拉取全量日誌,但是follower自身的leader-epoch-checkpoint文件還需要全量維護,因此就需要額外花精力去構建這個文件,否則當這個follower成為leader後,leader-epoch-checkpoint文件的部分缺失,會使其無法做出正常的判斷」這個AuxiliaryState其實就是leader的「leader eopch」及「producer-snapshot-ids」。可以通過兩種方式來實現:

  • 引入一個新的協議,專門從leader中拉取這個AuxiliaryState
  • 從遠端存儲中獲取這個AuxiliaryState

這裡更推薦後者,因為本身遠端存儲已經保留了這個欄位,且不需要在於leader的交互中引入新的協議

獲取目標offset的之前的日誌段的AuxiliaryState狀態需要以下2個步驟:

  • 需要拉取遠端日誌段的元數據
  • 需要在相應日誌段中拉取諸如leader epoch的記錄

當將一個日誌段(segment)搬移至遠端存儲後,leader broker同時需要將「leader epoch sequence」以及「producer id snapshot」追加到segment所在的目錄下。這些數據將會幫助follower來構建自己的「leader epoch sequence」以及「producer id snapshot」

譯者:原文其實反覆在強調這個事兒

因此,我們需要為這個副本引入一個相對應的新狀態,可以將其定義為BuildingRemoteLogAuxState。follower的拉取線程就如同切換Fetching或Truncating states狀態一樣,在每次執行時,都需要判斷一下,需要切換至哪個狀態

當一個follower嘗試拉取一個已經不在leader local 存儲的offset時,會收到leader返回的OffsetMovedToRemoteStorage錯誤,如果follower收到了這個狀態,將會:

  1. 通過調用API ListOffset來獲取leader的Earliest Local Offset (ELO) 以及 leader epoch (ELO-LE) 譯者:註意,ListOffset這個API將會發生改變,其返回的出參中將會攜帶這些信息
  2. 截斷自己的本地日誌以及AuxiliaryState
  3. 從Fetching狀態切換至BuildingRemoteLogAux狀態

處於BuildingRemoteLogAux狀態時,follower可以在以下兩個方案中二選一:

  • 方案1:
    • 通過不斷反覆調用FetchEarliestOffsetFromLeader API,從而獲取ELO-LE至leader中最早的leader epoch,然後構建follower本地的leader epoch。當遠端存儲上有很多任leader切換時,這個方案可能並不會很高效。不過這個方案的好處是,獲取leader epoch的操作完全在kafka內部,當遠端存儲出現短暫不可用時,follower仍然可以追趕leader併進入ISR
  • 方案2:
    • RLMM(RemoteLogMetadataManager)等待遠端的元數據,直到等到某個segment包含了ELO-LE
    • 抓取遠端存儲的leader epoch以及producer snapshot(使用遠端fetcher線程)譯者:多層存儲引入的工作線程
    • 獲取遠端存儲的leader epoch數據後,截取 [LSO, ELO] 部分,然後構建follower自己的cache

在構建完follower自己的leader epoch後,follower狀態轉換為Fetching,然後繼續從leader的ELO開始拉取數據。我們更傾向使用方案2,即從遠端存儲來獲取所需數據

Follower fetch 場景(包含日誌截斷的場景)

讓我們討論一下follower在嘗試從leader複製並從遠程存儲構建AuxiliaryState狀態時可能遇到的幾種情況

名詞定義:

OMTS : OffsetMovedToTieredStorage 譯者:offset已經不在leader中,通常是一個錯誤

ELO : Earliest-Local-Offset 譯者:local存儲中最早的offset

LE-x : Leader Epoch x, 譯者:leader epoch,不贅述

HW : High Watermark 譯者:高水位,kafka發明的詞,不贅述

seg-a-b: a remote segment with first-offset = a and last-offset = b 譯者:遠端存儲的某個segment日誌段,它的offse的區間

LE-x, y : A leader epoch sequence entry indicates leader-epoch x starts from offset y 譯者:leader epoch的某個區間

場景1:全新follower

現在假設某個全新的broker剛被加入集群,然後將其指派為某個partition的follower replica,這個follower肯定是沒有任何本地存儲數據的。它將會從offset為0的位置開始從leader抓取數據,如果offset為0的位點在leader中不存在的話,follower將會收到錯誤OFFSET_MOVED_TO_TIERED_STORAGE,然後follower將會給leader發送ListOffset API,並且在入參中攜帶參數timestamp = EARLIEST_LOCAL_TIMESTAMP,接著會收到leader返回的ELO(Earliest-Local-Offset) 譯者:多層存儲需要修改ListOffset協議

follower需要等待這個offset(leader的ELO)的返回,然後構建AuxiliaryState狀態,然後才能從leader拉取數據 譯者:又強調了構建覆核狀態的必要

步驟1:

抓取遠端segment信息,然後構建leader epoch

Broker A (Leader)

Broker B (Follower)

Remote Storage

RL metadata storage

3: msg 3 LE-1

4: msg 4 LE-1

5: msg 5 LE-2

6: msg 6 LE-2

7: msg 7 LE-3 (HW)



leader_epochs

LE-0, 0

LE-1, 3

LE-2, 5

LE-3, 7




1. Fetch LE-1, 0

2. Receives OMTS

3. Receives ELO 3, LE-1

4. Fetch remote segment info and build local leader epoch sequence until ELO



leader_epochs

LE-0, 0

LE-1, 3



seg-0-2, uuid-1

log:

0: msg 0 LE-0

1: msg 1 LE-0

2: msg 2 LE-0

epochs:

LE-0, 0



seg 3-5, uuid-2

log:

3: msg 3 LE-1

4: msg 4 LE-1

5: msg 5 LE-2

epochs:

LE-0, 0

LE-1, 3

LE-2, 5

seg-0-2, uuid-1

segment epochs

LE-0, 0



seg-3-5, uuid-2

segment epochs

LE-1, 3

LE-2, 5

步驟2:

繼續從leader拉取數據

Broker A (Leader)

Broker B (Follower)

Remote Storage

RL metadata storage

3: msg 3 LE-1

4: msg 4 LE-1

5: msg 5 LE-2

6: msg 6 LE-2

7: msg 7 LE-3 (HW)



leader_epochs

LE-0, 0

LE-1, 3

LE-2, 5

LE-3, 7




Fetch from ELO to HW

3: msg 3 LE-1

4: msg 4 LE-1

5: msg 5 LE-2

6: msg 6 LE-2

7: msg 7 LE-3 (HW)

leader_epochs

LE-0, 0

LE-1, 3

LE-2, 5

LE-3, 7

seg-0-2, uuid-1

log:

0: msg 0 LE-0

1: msg 1 LE-0

2: msg 2 LE-0

epochs:

LE-0, 0



seg 3-5, uuid-2

log:

3: msg 3 LE-1

4: msg 4 LE-1

5: msg 5 LE-2

epochs:

LE-0, 0

LE-1, 3

LE-2, 5

seg-0-2, uuid-1

segment epochs

LE-0, 0



seg-3-5, uuid-2

segment epochs

LE-1, 3

LE-2, 5

場景2:out-of-sync follower catching up

一個follower正在嘗試追趕leader,然後leader對應的日誌段segment已經轉移至了遠端存儲。我們以目標日誌段是否在本地存儲來分為2種情況來討論

  • 本地segment存在,而且本地最新的offset要比leader的ELO大
    • 這種場景,本地存儲已有,follower跟常規方式一樣進行拉取即可
  • 本地segment不存在,或者最新的offset要比leader的ELO小
    • 這種場景,本地的日誌段可能因為日誌過期已經刪除,或者是因為follower已經離線了很長一段時間。然後follower拉取數據時,將會收到OFFSET_MOVED_TO_TIERED_STORAGE錯誤,然後follower將不得不截斷自己所有的本地日誌,因為這些數據在leader已經標記為過期

步驟1:

out-of-sync follower (broker B) 本地的offset存儲到了3

Broker A (Leader)

Broker B (Follower)

Remote Storage

RL metadata storage

0: msg 0 LE-0

1: msg 1 LE-0

2: msg 2 LE-0

3: msg 3 LE-1

4: msg 4 LE-1

5: msg 5 LE-2

6: msg 6 LE-2

7: msg 7 LE-3

8: msg 8 LE-3

9: msg 9 LE-3 (HW)





leader_epochs

LE-0, 0

LE-1, 3

LE-2, 5

LE-3, 7

0: msg 0 LE-0

1: msg 1 LE-0

2: msg 2 LE-0

3: msg 3 LE-1

leader_epochs

LE-0, 0

LE-1, 3

1. Because the latest leader epoch in the local storage (LE-1) does not equal the current leader epoch (LE-3). The follower starts from the Truncating state.

2. fetchLeaderEpochEndOffsets(LE-1) returns 5, which is larger than the latest local offset. With the existing truncation logic, the local log is not truncated and it moves to Fetching state.





seg-0-2, uuid-1

log:

0: msg 0 LE-0

1: msg 1 LE-0

2: msg 2 LE-0

epochs:

LE-0, 0



seg 3-5, uuid-2

log:

3: msg 3 LE-1

4: msg 4 LE-1

5: msg 5 LE-2

epochs:

LE-0, 0

LE-1, 3

LE-2, 5

seg-0-2, uuid-1

segment epochs

LE-0, 0



seg-3-5, uuid-2

segment epochs

LE-1, 3

LE-2, 5



步驟2:

leader的本地日誌段因為數據過期而已經刪除,然後follower開始嘗試追上leader

Broker A (Leader)

Broker B (Follower)

Remote Storage

RL metadata storage

9: msg 9 LE-3

10: msg 10 LE-3

11: msg 11 LE-3 (HW)




[segments till offset 8 were deleted]




leader_epochs

LE-0, 0

LE-1, 3

LE-2, 5

LE-3, 7

0: msg 0 LE-0

1: msg 1 LE-0

2: msg 2 LE-0

3: msg 3 LE-1

leader_epochs

LE-0, 0

LE-1, 3



<Fetch State>

1. Fetch from leader LE-1, 4

2. Receives OMTS, truncate local segments.

3. Fetch ELO, Receives ELO 9, LE-3 and moves to BuildingRemoteLogAux state





seg-0-2, uuid-1

log:

0: msg 0 LE-0

1: msg 1 LE-0

2: msg 2 LE-0

epochs:

LE-0, 0



seg 3-5, uuid-2

log:

3: msg 3 LE-1

4: msg 4 LE-1

5: msg 5 LE-2

epochs:

LE-0, 0

LE-1, 3

LE-2, 5



Seg 6-8, uuid-3, LE-3

log:

6: msg 6 LE-2

7: msg 7 LE-3

8: msg 8 LE-3

epochs:

LE-0, 0

LE-1, 3

LE-2, 5

LE-3, 7

seg-0-2, uuid-1

segment epochs

LE-0, 0



seg-3-5, uuid-2

segment epochs

LE-1, 3

LE-2, 5



seg-6-8, uuid-3

segment epochs

LE-2, 5

LE-3, 7

步驟3:

刪除本地數據後,將會轉換為場景1一樣的case

Broker A (Leader)

Broker B (Follower)

Remote Storage

RL metadata storage

9: msg 9 LE-3

10: msg 10 LE-3

11: msg 11 LE-3 (HW)




[segments till offset 8 were deleted]




leader_epochs

LE-0, 0

LE-1, 3

LE-2, 5

LE-3, 7

1. follower rebuilds leader epoch sequence up to LE-3 using remote segment metadata and remote data

leader_epochs

LE-0, 0

LE-1, 3

LE-2, 5

LE-3, 7



2. follower continue fetching from the leader from ELO (9, LE-3)

9: msg 9 LE-3

10: msg 10 LE-3

11: msg 11 LE-3 (HW)












seg-0-2, uuid-1

log:

0: msg 0 LE-0

1: msg 1 LE-0

2: msg 2 LE-0

epochs:

LE-0, 0



seg 3-5, uuid-2

log:

3: msg 3 LE-1

4: msg 4 LE-1

5: msg 5 LE-2

epochs:

LE-0, 0

LE-1, 3

LE-2, 5



Seg 6-8, uuid-3, LE-3

log:

6: msg 6 LE-2

7: msg 7 LE-3

8: msg 8 LE-3

epochs:

LE-0, 0

LE-1, 3

LE-2, 5

LE-3, 7

seg-0-2, uuid-1

segment epochs

LE-0, 0



seg-3-5, uuid-2

segment epochs

LE-1, 3

LE-2, 5



seg-6-8, uuid-3

segment epochs

LE-2, 5

LE-3, 7

場景3:Multiple hard failures

步驟1:

Broker A已經將第一個segment轉移至了遠端存儲

Broker A (Leader)

Broker B

Remote Storage

RL metadata storage

0: msg 0 LE-0

1: msg 1 LE-0

2: msg 2 LE-0 (HW)

leader_epochs

LE-0, 0

0: msg 0 LE-0

1: msg 1 LE-0

2: msg 2 LE-0 (HW)

leader_epochs

LE-0,

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 華為攜手伙伴和開發者駛向更廣闊的的未來,一起打造一個高級簡約、極致流暢、隱私安全、開放共贏的新生態體系。 ...
  • 該組件還有一個名為 `selectable` 的屬性,用於控制選項是否可選。如果要實現選項變為灰色且不可選的效果,需要同時將選項的 `disabled` 屬性設置為 `true`,將 `seletable` 屬性設置為 `false`。 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 翻轉圖像是在視覺上比較兩個不同圖像的常用方法。單擊其中一個將翻轉它,並顯示另一個圖像。 佈局 佈局結構如下: <div class="flipping-images"> <div class="flipping-images__inner ...
  • 一、實現方案 單獨貼代碼可能容易混亂,所以這裡只講實現思路,代碼放在最後彙總了下。 想要實現一個簡單的工業園區、主要包含的內容是一個大樓、左右兩片停車位、四條道路以及多個可在道路上隨機移動的車輛、遇到停車位時隨機選擇是否要停車,簡單設計圖如下 二、實現步奏 2.1 引入環境,天空和地面 引入天空有三 ...
  • 前言 有時出現的線上bug在測試環境死活都不能復現,靠review代碼猜測bug出現的原因,然後盲改代碼直接線上上測試明顯不靠譜。這時我們就需要在生產環境中debug代碼,快速找到bug的原因,然後將鍋丟出去。 生產環境的代碼一般都是關閉source map和經過混淆的,那麼如何進行debug代碼呢 ...
  • 在接入小程式過程中會遇到需要將 H5 頁面集成到小程式中情況,今天我們就來聊一聊怎麼把 H5 頁面塞到小程式中。 本篇文章將會從下麵這幾個方面來介紹: 小程式承載頁面的前期準備 小程式如何承載 H5 小程式和 H5 頁面如何通訊 小程式和 H5 頁面的相互跳轉 小程式承載頁面的前期準備 首先介紹下我 ...
  • Vue3 對 diff 過程進行了大升級,利用 最長遞增子序列演算法 去計算最少移動dom,儘可能少的做移動節點位置操作! ...
  • 在當今的互聯網時代,微服務架構已經成為許多企業選擇的架構模式,它能夠提高系統的靈活性、可維護性和可擴展性。然而,微服務架構下的高可用性和彈性擴展是一個複雜的挑戰。本文將介紹如何利用容器與中間件來實現微服務架構下的高可用性和彈性擴展的解決方案。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...