Generation Clock模式解決方案
作者: Unmesh Joshi
譯者: java達(dá)人
一個(gè)單調(diào)遞增的數(shù)字,表示服務(wù)器的generation 。
問(wèn)題
在領(lǐng)導(dǎo)者和追隨者設(shè)置中,有可能會(huì)出現(xiàn)領(lǐng)導(dǎo)者與追隨者暫時(shí)斷開(kāi)聯(lián)系的情況。leader進(jìn)程中可能會(huì)出現(xiàn)垃圾收集暫停,或者暫時(shí)的網(wǎng)絡(luò)中斷,導(dǎo)致leader和follower之間的連接斷開(kāi)。在這種情況下,領(lǐng)導(dǎo)者進(jìn)程仍在運(yùn)行,在暫停或網(wǎng)絡(luò)中斷結(jié)束后,它將嘗試向追隨者發(fā)送復(fù)制請(qǐng)求。這很危險(xiǎn),因?yàn)榧旱钠渌糠挚赡芤呀?jīng)選擇了新的leader并接受了來(lái)自客戶(hù)機(jī)的請(qǐng)求。對(duì)于集群的其他部分來(lái)說(shuō),檢測(cè)來(lái)自舊leader的任何請(qǐng)求非常重要。舊的leader本身也應(yīng)該能夠檢測(cè)到它暫時(shí)與集群斷開(kāi)了連接,并采取必要的糾正措施放棄領(lǐng)導(dǎo)者身份。
解決方案
Generation Clock模式是Lamport時(shí)間戳的一個(gè)示例:這是一種簡(jiǎn)單的技術(shù),用于確定跨一組進(jìn)程的事件順序,而不依賴(lài)于系統(tǒng)時(shí)鐘。每個(gè)進(jìn)程維護(hù)一個(gè)整數(shù)計(jì)數(shù)器,該計(jì)數(shù)器在該進(jìn)程執(zhí)行每個(gè)操作后遞增。每個(gè)進(jìn)程還將這個(gè)整數(shù)連同進(jìn)程交換的消息一起發(fā)送給其他進(jìn)程。接收消息的進(jìn)程通過(guò)獲取自己的計(jì)數(shù)器和消息的整數(shù)值之間的最大值來(lái)設(shè)置自己的整數(shù)計(jì)數(shù)器。這樣,任何進(jìn)程都可以通過(guò)比較相關(guān)的整數(shù)來(lái)確定哪個(gè)操作在另一個(gè)操作之前發(fā)生。如果消息在多個(gè)進(jìn)程之間交換,也可以對(duì)多個(gè)進(jìn)程之間的操作進(jìn)行比較?梢赃@樣比較的行為被稱(chēng)為“因果關(guān)系”。
維護(hù)一個(gè)單調(diào)遞增的數(shù)字表示服務(wù)器的generation 。每次新領(lǐng)導(dǎo)者選舉時(shí),都應(yīng)該以增加一個(gè)generation 為標(biāo)志。generation 需要在服務(wù)器重新啟動(dòng)之后可用,因此它與 Write-Ahead Log中的每個(gè)條目一起存儲(chǔ)。正如在High-Water Mark中所討論的,追隨者使用此信息來(lái)查找日志中的沖突條目。
在啟動(dòng)時(shí),服務(wù)器從日志中讀取最近已知generation 。
class ReplicationModule… this.replicationState = new ReplicationState(config, wal.getLastLogEntryGeneration());
有了領(lǐng)導(dǎo)者和追隨者,服務(wù)器就會(huì)在每次有新的領(lǐng)導(dǎo)者選舉時(shí)遞增generation 。
class ReplicationModule… private void startLeaderElection() { replicationState.setGeneration(replicationState.getGeneration() + 1); registerSelfVote(); requestVoteFrom(followers); }
服務(wù)器將生成的generation 作為投票請(qǐng)求的一部分發(fā)送到其他服務(wù)器。這樣,在一個(gè)成功的領(lǐng)導(dǎo)者選舉后,所有的服務(wù)器都有相同的generation。一旦領(lǐng)導(dǎo)被選出來(lái),追隨者們就會(huì)被告知新generation 的情況
follower (class ReplicationModule...) private void becomeFollower(Long generation) { replicationState.setGeneration(generation); transitionTo(ServerRole.FOLLOWING); }
之后,領(lǐng)導(dǎo)者在發(fā)送給追隨者的每個(gè)請(qǐng)求中都包含了generation。它將generation包含在每個(gè)心跳消息以及發(fā)送給追隨者的復(fù)制請(qǐng)求中。
Leader在其Write-Ahead Log中保留每一個(gè)條目的generation
leader (class ReplicationModule...) Long appendToLocalLog(byte[] data) { var logEntryId = wal.getLastLogEntryId() + 1; var logEntry = new WALEntry(logEntryId, data, EntryType.DATA, replicationState.getGeneration()); return wal.writeEntry(logEntry); }
這樣,作為L(zhǎng)eader和follower復(fù)制機(jī)制的一部分,它也被持久化到follower日志中
如果一個(gè)追隨者從一個(gè)被廢棄的領(lǐng)導(dǎo)者那里得到一個(gè)信息,這個(gè)追隨者可以辨別出來(lái),因?yàn)樗膅eneration 太小了。追隨者然后返回一個(gè)失敗的響應(yīng)。
follower (class ReplicationModule...) Long currentGeneration = replicationState.getGeneration(); if (currentGeneration > replicationRequest.getGeneration()) { return new ReplicationResponse(FAILED, serverId(), currentGeneration, wal.getLastLogEntryId()); }
當(dāng)一個(gè)領(lǐng)導(dǎo)者得到這樣一個(gè)失敗的響應(yīng)時(shí),他就變成了一個(gè)跟隨者,并期待來(lái)自新領(lǐng)導(dǎo)者的交流。
Old leader (class ReplicationModule...) if (!response.isSucceeded()) { stepDownIfHigherGenerationResponse(response); return; }
private void stepDownIfHigherGenerationResponse(ReplicationResponse replicationResponse) { if (replicationResponse.getGeneration() > replicationState.getGeneration()) { becomeFollower(replicationResponse.getGeneration()); } }
考慮下面的例子。在三個(gè)服務(wù)器集群中,leader1是現(xiàn)有的leader。集群中的所有服務(wù)器的generation都為1。Leader1向追隨者發(fā)送連續(xù)的心跳。Leader1有一個(gè)很長(zhǎng)的垃圾收集暫停時(shí)間,比如5秒。追隨者沒(méi)有得到一個(gè)心跳,超時(shí)后選舉一個(gè)新的領(lǐng)導(dǎo)者。新領(lǐng)導(dǎo)者將generation增加到2。垃圾收集暫停結(jié)束后,leader1繼續(xù)向其他服務(wù)器發(fā)送請(qǐng)求。generation為2的追隨者和新領(lǐng)導(dǎo)者拒絕請(qǐng)求,并發(fā)送失敗響應(yīng),帶上generation2。leader1處理失敗響應(yīng),并回退做一個(gè)跟隨者,generation 更新為2。
例子
Raft Raft使用Term的概念來(lái)標(biāo)記leader generation。
Zab 在Zookeeper中,epoch號(hào)作為每個(gè)事務(wù)id的一部分進(jìn)行維護(hù)。因此,在Zookeeper中持久化的每個(gè)事務(wù)都有一個(gè)以epoch標(biāo)記的generation。
Cassandra 在Cassandra中,每個(gè)服務(wù)器存儲(chǔ)一個(gè)generation編號(hào),該編號(hào)在服務(wù)器每次重啟時(shí)遞增。generation信息保存在系統(tǒng)密鑰空間中,并作為gossip消息的一部分傳播到其他服務(wù)器。接收到gossip消息的服務(wù)器可以比較它所知道的generation值和gossip消息中的generation值。如果gossip消息中的generation值較高,則知道服務(wù)器已重啟,然后丟棄為該服務(wù)器維護(hù)的所有狀態(tài),并請(qǐng)求新的狀態(tài)。
Kafka中的Epoch 在Kafka中,每次為Kafka集群選擇一個(gè)新控制器時(shí),都會(huì)創(chuàng)建一個(gè)epoch數(shù)并存儲(chǔ)在Zookeeper中。epoch包含在從控制器發(fā)送到集群中其他服務(wù)器的每個(gè)請(qǐng)求中。另一個(gè)稱(chēng)為L(zhǎng)eaderEpoch的epoch被維護(hù),以了解追隨者分區(qū)High-Water Mark是否落后。

發(fā)表評(píng)論
登錄
手機(jī)
驗(yàn)證碼
立即登錄即可訪(fǎng)問(wèn)所有OFweek服務(wù)
還不是會(huì)員?免費(fèi)注冊(cè)
忘記密碼請(qǐng)輸入評(píng)論內(nèi)容...
請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字
圖片新聞
-
馬云重返一線(xiàn)督戰(zhàn),阿里重啟創(chuàng)始人模式
-
機(jī)器人奧運(yùn)會(huì)戰(zhàn)報(bào):宇樹(shù)機(jī)器人摘下首金,天工Ultra搶走首位“百米飛人”
-
存儲(chǔ)圈掐架!江波龍起訴佰維,索賠121萬(wàn)
-
長(zhǎng)安汽車(chē)母公司突然更名:從“中國(guó)長(zhǎng)安”到“辰致科技”
-
豆包前負(fù)責(zé)人喬木出軌BP后續(xù):均被辭退
-
字節(jié)AI Lab負(fù)責(zé)人李航卸任后返聘,Seed進(jìn)入調(diào)整期
-
員工持股爆雷?廣汽埃安緊急回應(yīng)
-
中國(guó)“智造”背后的「關(guān)鍵力量」
最新活動(dòng)更多
-
10月23日火熱報(bào)名中>> 2025是德科技創(chuàng)新技術(shù)峰會(huì)
-
10月23日立即報(bào)名>> Works With 開(kāi)發(fā)者大會(huì)深圳站
-
10月24日立即參評(píng)>> 【評(píng)選】維科杯·OFweek 2025(第十屆)物聯(lián)網(wǎng)行業(yè)年度評(píng)選
-
即日-11.25立即下載>>> 費(fèi)斯托白皮書(shū)《柔性:汽車(chē)生產(chǎn)未來(lái)的關(guān)鍵》
-
11月27日立即報(bào)名>> 【工程師系列】汽車(chē)電子技術(shù)在線(xiàn)大會(huì)
-
12月18日立即報(bào)名>> 【線(xiàn)下會(huì)議】OFweek 2025(第十屆)物聯(lián)網(wǎng)產(chǎn)業(yè)大會(huì)
推薦專(zhuān)題
- 1 特斯拉工人被故障機(jī)器人打成重傷,索賠3.6億
- 2 【行業(yè)深度研究】退居幕后四年后,張一鳴終于把算法公司變成AI公司?
- 3 AI 時(shí)代,阿里云想當(dāng)“安卓” ,那誰(shuí)是“蘋(píng)果”?
- 4 硬剛英偉達(dá)!華為發(fā)布全球最強(qiáng)算力超節(jié)點(diǎn)和集群
- 5 機(jī)器人9月大事件|3家國(guó)產(chǎn)機(jī)器人沖刺IPO,行業(yè)交付與融資再創(chuàng)新高!
- 6 谷歌“香蕉”爆火啟示:國(guó)產(chǎn)垂類(lèi)AI的危機(jī)還是轉(zhuǎn)機(jī)?
- 7 00后華裔女生靠?jī)刹緼I電影狂賺7.8億人民幣,AI正式進(jìn)軍好萊塢
- 8 美光:AI Capex瘋投不止,終于要拉起存儲(chǔ)超級(jí)周期了?
- 9 華為已殺入!AI領(lǐng)域最熱黃金賽道,大廠(chǎng)的數(shù)字人美女讓我一夜沒(méi)睡著覺(jué)
- 10 隱退4年后,張一鳴久違現(xiàn)身!互聯(lián)網(wǎng)大佬正集體殺回