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
  • 在C#中使用SQL Server實現事務的ACID(原子性、一致性、隔離性、持久性)屬性和使用資料庫鎖(悲觀鎖和樂觀鎖)時,你可以通過ADO.NET的SqlConnection和SqlTransaction類來實現。下麵是一些示例和概念說明。 實現ACID事務 ACID屬性是事務處理的四個基本特征, ...
  • 我們在《SqlSugar開發框架》中,Winform界面開發部分往往也用到了自定義的用戶控制項,對應一些特殊的界面或者常用到的一些局部界面內容,我們可以使用自定義的用戶控制項來提高界面的統一性,同時也增強了使用的便利性。如我們Winform界面中用到的分頁控制項、附件顯示內容、以及一些公司、部門、菜單的下... ...
  • 在本篇教程中,我們學習瞭如何在 Taurus.MVC WebMVC 中進行數據綁定操作。我們還學習瞭如何使用 ${屬性名稱} CMS 語法來綁定頁面上的元素與 Model 中的屬性。通過這些步驟,我們成功實現了一個簡單的數據綁定示例。 ...
  • 是在MVVM中用來傳遞消息的一種方式。它是在MVVMLight框架中提供的一個實現了IMessenger介面的類,可以用來在ViewModel之間、ViewModel和View之間傳遞消息。 Send 接受一個泛型參數,表示要發送的消息內容。 Register 方法用於註冊某個對象接收消息。 pub ...
  • 概述:在WPF中,通過EventHandler可實現基礎和高級的UI更新方式。基礎用法涉及在類中定義事件,併在UI中訂閱以執行更新操作。高級用法藉助Dispatcher類,確保在非UI線程上執行操作後,通過UI線程更新界面。這兩種方法提供了靈活而可靠的UI更新機制。 在WPF(Windows Pre ...
  • 概述:本文介紹了在C#程式開發中如何利用自定義擴展方法測量代碼執行時間。通過使用簡單的Action委托,開發者可以輕鬆獲取代碼塊的執行時間,幫助優化性能、驗證演算法效率以及監控系統性能。這種通用方法提供了一種便捷而有效的方式,有助於提高開發效率和代碼質量。 在軟體開發中,瞭解代碼執行時間是優化程式性能 ...
  • 概述:Cron表達式是一種強大的定時任務調度工具,通過配置不同欄位實現靈活的時間規定。在.NET中,Quartz庫提供了簡便的方式配置Cron表達式,實現精準的定時任務調度。這種靈活性和可擴展性使得開發者能夠根據需求輕鬆地制定和管理定時任務,例如每天備份系統日誌或其他重要操作。 Cron表達式詳解 ...
  • 概述:.NET提供多種定時器,如System.Windows.Forms.Timer適用於UI,System.Web.UI.Timer用於Web,System.Diagnostics.Timer用於性能監控,System.Threading.Timer和System.Timers.Timer用於一般 ...
  • 問題背景 有同事聯繫我說,在生產環境上,訪問不了我負責的common服務,然後我去檢查common服務的health endpoint, 沒問題,然後我問了下異常,timeout導致的System.OperationCanceledException。那大概率是客戶端的問題,會不會是埠耗盡,用ne ...
  • 前言: 在本篇 Taurus.MVC WebMVC 入門開發教程的第四篇文章中, 我們將學習如何實現數據列表的綁定,通過使用 List<Model> 來展示多個數據項。 我們將繼續使用 Taurus.Mvc 命名空間,同時探討如何在視圖中綁定並顯示一個 Model 列表。 步驟1:創建 Model ...