成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Go存儲(chǔ)怎么寫?深度解析etcd存儲(chǔ)設(shè)計(jì)

存儲(chǔ) 存儲(chǔ)軟件
etcd是用于共享配置和服務(wù)發(fā)現(xiàn)的分布式,一致性的KV存儲(chǔ)系統(tǒng),在CoreOS和Kubernetes等開(kāi)源項(xiàng)目中廣泛使用。本文作者深入分析了etcd存儲(chǔ)模塊的設(shè)計(jì)和實(shí)現(xiàn),對(duì)于深入學(xué)習(xí)Go存儲(chǔ)有很大參考作用。

 概覽

下圖中展示了etcd如何處理一個(gè)客戶端請(qǐng)求的涉及到的模塊和流程。圖中淡紫色的矩形表示etcd,它包括如下幾個(gè)模塊:

  • etcd server:對(duì)外接收客戶端的請(qǐng)求,對(duì)應(yīng)etcd代碼中的etcdserver目錄,其中還有一個(gè)raft.go的模塊與etcd-raft庫(kù)進(jìn)行通信。etcdserver中與存儲(chǔ)相關(guān)的模塊是applierV3,這里封裝了V3版本的數(shù)據(jù)存儲(chǔ),WAL(write ahead log),用于寫數(shù)據(jù)日志,etcd啟動(dòng)時(shí)會(huì)根據(jù)這部分內(nèi)容進(jìn)行恢復(fù)。
  • etcd raft:etcd的raft庫(kù),前面的文章已經(jīng)具體分析過(guò)這部分代碼。除了與本節(jié)點(diǎn)的etcd server通信之外,還與集群中的其他etcd server進(jìn)行交互做一致性數(shù)據(jù)同步的工作(在圖中集群中其他etcd服務(wù)用橙色的橢圓表示)。

 

在上圖中,一個(gè)請(qǐng)求與一個(gè)etcd集群交互的主要流程分為兩大部分:

  1. 寫數(shù)據(jù)到某個(gè)etcd server中。
  2. 該etcd server與集群中的其他etcd節(jié)點(diǎn)進(jìn)行交互,當(dāng)確保數(shù)據(jù)已經(jīng)被存儲(chǔ)之后應(yīng)答客戶端。

請(qǐng)求流程劃分為了以下的子步驟:

  • 1.1:etcd server收到客戶端請(qǐng)求。
  • 1.2:etcd server將請(qǐng)求發(fā)送給本模塊中的raft.go,這里負(fù)責(zé)與etcd raft模塊進(jìn)行通信。
  • 1.3:raft.go將數(shù)據(jù)封裝成raft日志的形式提交給raft模塊。
  • 1.4:raft模塊會(huì)首先保存到raftLog的unstable存儲(chǔ)部分。
  • 1.5:raft模塊通過(guò)raft協(xié)議與集群中其他etcd節(jié)點(diǎn)進(jìn)行交互。

注意在以上流程中,假設(shè)這里寫入數(shù)據(jù)的etcd是leader節(jié)點(diǎn),因?yàn)樵趓aft協(xié)議中,如果提交數(shù)據(jù)到非leader節(jié)點(diǎn)的話需要路由到etcd leader節(jié)點(diǎn)去。

而應(yīng)答步驟如下:

  • 2.1:集群中其他節(jié)點(diǎn)向leader節(jié)點(diǎn)應(yīng)答接收這條日志數(shù)據(jù)。
  • 2.2:當(dāng)超過(guò)集群半數(shù)以上節(jié)點(diǎn)應(yīng)答接收這條日志數(shù)據(jù)時(shí),etcd raft通過(guò)Ready結(jié)構(gòu)體通知etcd server中的raft該日志數(shù)據(jù)已經(jīng)commit。
  • 2.3:raft.go收到Ready數(shù)據(jù)將首先將這條日志寫入到WAL模塊中。
  • 2.4:通知最上層的etcd server該日志已經(jīng)commit。
  • 2.5:etcd server調(diào)用applierV3模塊將日志寫入持久化存儲(chǔ)中。
  • 2.6:etcd server應(yīng)答客戶端該數(shù)據(jù)寫入成功。
  • 2.7:最后etcd server調(diào)用etcd raft,修改其raftLog模塊的數(shù)據(jù),將這條日志寫入到raftLog的storage中。

從上面的流程可以看到

  • etcd raft模塊在應(yīng)答某條日志數(shù)據(jù)已經(jīng)commit之后,是首先寫入到WAL模塊中的,因?yàn)檫@個(gè)模塊只是添加一條日志,所以速度會(huì)很快,即使在后面applierV3寫入失敗,重啟的時(shí)候也可以根據(jù)WAL模塊中的日志數(shù)據(jù)進(jìn)行恢復(fù)。
  • etcd raft中的raftLog,按照前面文章的分析,其中的數(shù)據(jù)是保存到內(nèi)存中的,重啟即失效,上層應(yīng)用真實(shí)的數(shù)據(jù)是持久化保存到WAL和applierV3中的。

以下就來(lái)分析etcd server與這部分相關(guān)的幾個(gè)模塊。

etcd server與raft的交互

EtcdServer結(jié)構(gòu)體,負(fù)責(zé)對(duì)外與客戶端進(jìn)行通信。內(nèi)部有一個(gè)raftNode結(jié)構(gòu)的成員,負(fù)責(zé)與etcd的raft庫(kù)進(jìn)行交互。

etcd V3版本的API,通過(guò)GRPC協(xié)議與客戶端進(jìn)行交互,其相關(guān)代碼在etcdserver/v3_server.go中。以一次Put請(qǐng)求為例,最后將會(huì)調(diào)用的代碼在函數(shù)EtcdServer::processInternalRaftRequestOnce中,代碼的主要流程分析如下。

 

  1. 拿到當(dāng)前raft中的apply和commit索引,如果commit索引比apply索引超出太多,說(shuō)明當(dāng)前有很多數(shù)據(jù)都沒(méi)有apply,返回ErrTooManyRequests錯(cuò)誤。
  2. 調(diào)用s.reqIDGen.Next()函數(shù)生成一個(gè)針對(duì)當(dāng)前請(qǐng)求的ID,注意這個(gè)ID并不是一個(gè)隨機(jī)數(shù)而是一個(gè)嚴(yán)格遞增的整數(shù)。同時(shí)將請(qǐng)求序列化為byte數(shù)據(jù),這會(huì)做為raft的數(shù)據(jù)進(jìn)行存儲(chǔ)。
  3. 根據(jù)第2步中的ID,調(diào)用Wait.Register函數(shù)進(jìn)行注冊(cè),這會(huì)返回一個(gè)用于通知結(jié)果的channel,后續(xù)就通過(guò)監(jiān)聽(tīng)該channel來(lái)確定是否成功儲(chǔ)存了提交的值。
  4. 調(diào)用Raft.Process函數(shù)提交數(shù)據(jù),這里傳入的參數(shù)除了前面序列化的數(shù)據(jù)之外,還有使用超時(shí)時(shí)間創(chuàng)建的Context。
  5. 監(jiān)聽(tīng)前面的Channel以及Context對(duì)象: a. 如果context.Done返回,說(shuō)明數(shù)據(jù)提交超時(shí),使用s.parseProposeCtxErr函數(shù)返回具體的錯(cuò)誤。 b. 如果channel返回,說(shuō)明已經(jīng)提交成功。

從以上的流程可以看出,在調(diào)用Raft.Process函數(shù)向Raft庫(kù)提交數(shù)據(jù)之后,等待被喚醒的Channel才是正常提交數(shù)據(jù)成功的路徑。

在EtcdServer.run函數(shù)中,最終會(huì)進(jìn)入一個(gè)死循環(huán)中,等待raftNode.apply返回的channel被喚醒,而raftNode繼承了raft.Node的實(shí)現(xiàn),從前面分析etcd raft的流程中可以明白,EtcdServer就是在向raft庫(kù)提交了數(shù)據(jù)之后,做為其上層消費(fèi)Ready數(shù)據(jù)的應(yīng)用層。

自此,整體的流程大體已經(jīng)清晰:

  1. EtcdServer對(duì)外通過(guò)GRPC協(xié)議接收客戶端請(qǐng)求,對(duì)內(nèi)有一個(gè)raftNode類型的成員,該類型繼承了raft.Node的實(shí)現(xiàn)。
  2. 客戶端通過(guò)EtcdServer提交的數(shù)據(jù)修改都會(huì)通過(guò)raftNode來(lái)提交,而EtcdServer本身通過(guò)監(jiān)聽(tīng)channel與raft庫(kù)進(jìn)行通信,由Ready結(jié)構(gòu)體來(lái)通過(guò)EtcdServer哪些數(shù)據(jù)已經(jīng)提交成功。
  3. 由于每個(gè)請(qǐng)求都會(huì)一個(gè)對(duì)應(yīng)的ID,ID綁定了Channel,所以提交成功的請(qǐng)求通過(guò)ID找到對(duì)應(yīng)的Channel來(lái)喚醒提交流程,最后通知客戶端提交數(shù)據(jù)成功。

WAL

以上介紹了EtcdServer的大體流程,接下來(lái)看WAL的實(shí)現(xiàn)。

前面已經(jīng)分析過(guò)了,etcd raft提交數(shù)據(jù)成功之后,將通知上面的應(yīng)用層(在這里就是EtcdServer),然后再進(jìn)行持久化數(shù)據(jù)存儲(chǔ)。而數(shù)據(jù)的持久化可能會(huì)花費(fèi)一些時(shí)間,因此在應(yīng)答應(yīng)用層之前,EtcdServer中的raftNode會(huì)首先將這些數(shù)據(jù)寫入WAL日志中。這樣即使在做持久化的時(shí)候數(shù)據(jù)丟失了,啟動(dòng)恢復(fù)的時(shí)候也可以根據(jù)WAL的日志進(jìn)行數(shù)據(jù)恢復(fù)。

etcdserver模塊中,給raftNode用于寫WAL日志的工作,交給了接口Storage來(lái)完成,而這個(gè)接口由storage來(lái)具體實(shí)現(xiàn):

 

可以看到,這個(gè)結(jié)構(gòu)體組合了WAL和snap.Snapshotter結(jié)構(gòu),Snapshotter負(fù)責(zé)的是存儲(chǔ)快照數(shù)據(jù)。

WAL日志文件中,每條日志記錄有以下的類型:

  1. Type:日志記錄類型,下面詳細(xì)解釋都有哪些類型。
  2. Crc:這一條日志記錄的校驗(yàn)數(shù)據(jù)。
  3. Data:真正的數(shù)據(jù),根據(jù)類型不同存儲(chǔ)的數(shù)據(jù)也不同。

日志記錄又有如下的類型:

  1. metadataType:存儲(chǔ)的是元數(shù)據(jù)(metadata),每個(gè)WAL文件開(kāi)頭都有這類型的一條記錄數(shù)據(jù)。
  2. entryType:保存的是raft的數(shù)據(jù),也就是客戶端提交上來(lái)并且已經(jīng)commit的數(shù)據(jù)。
  3. stateType:保存的是當(dāng)前集群的狀態(tài)信息,即前面提到的HardState。
  4. crcType:校驗(yàn)數(shù)據(jù)。
  5. snapshotType:快照數(shù)據(jù)。

etcd使用兩個(gè)目錄分別存放WAL文件以及快照文件。其中,WAL文件的文件名格式是“16位的WAL文件編號(hào)-該WAL第一條entry數(shù)據(jù)的index號(hào).wal”,這樣就能從WAL文件名知道該WAL文件中保存的entry數(shù)據(jù)至少大于什么索引號(hào)。而快照文件名的格式則是“16位的快照數(shù)據(jù)最后一條日志記錄任期號(hào)-16位的快照數(shù)據(jù)最后一條記錄的索引號(hào).snap”。

Etcd會(huì)管理WAL目錄中的所有WAL文件,但是在生成快照文件之后,在快照數(shù)據(jù)之前的WAL文件將被清除掉,保證磁盤不會(huì)一直增長(zhǎng)。

比如當(dāng)前etcd中有三個(gè)WAL文件,可以從這些文件的文件名知道其中存放數(shù)據(jù)的索引范圍。

 

在生成快照文件之后,此時(shí)就只剩一個(gè)WAL文件和一個(gè)快照文件了:

 

那么,又是在什么情況下生成快照文件呢?Etcdserver在主循環(huán)中通過(guò)監(jiān)聽(tīng)channel獲知當(dāng)前raft協(xié)議返回的Ready數(shù)據(jù),此時(shí)會(huì)做判斷如果當(dāng)前保存的快照數(shù)據(jù)索引距離上一次已經(jīng)超過(guò)一個(gè)閾值(EtcdServer.snapCount),此時(shí)就從raft的存儲(chǔ)中生成一份當(dāng)前的快照數(shù)據(jù),寫入快照文件成功之后,就可以將這之前的WAL文件釋放了。

以上流程和對(duì)應(yīng)的具體函數(shù)見(jiàn)下面的流程圖。

 

backend store的實(shí)現(xiàn)

revision概念

Etcd存儲(chǔ)數(shù)據(jù)時(shí),并不是像其他的KV存儲(chǔ)那樣,存放數(shù)據(jù)的鍵做為key,而是以數(shù)據(jù)的revision做為key,鍵值做為數(shù)據(jù)來(lái)存放。如何理解revision這個(gè)概念,以下面的例子來(lái)說(shuō)明。

比如通過(guò)批量接口兩次更新兩對(duì)鍵值,第一次寫入數(shù)據(jù)時(shí),寫入

 

而在第二次更新寫入數(shù)據(jù)

 

其中revision有兩部分組成,第一部分成為main revision,每次事務(wù)遞增1;第二部分稱為sub revision,一個(gè)事務(wù)內(nèi)的一次操作遞增1。 兩者結(jié)合,就能保證每次key唯一而且是遞增的。

 

但是,就客戶端看來(lái),每次操作的時(shí)候是根據(jù)Key來(lái)進(jìn)行操作的,所以這里就需要一個(gè)Key映射到當(dāng)前revision的操作了,為了做到這個(gè)映射關(guān)系,Etcd引入了一個(gè)內(nèi)存中的Btree索引,整個(gè)操作過(guò)程如下面的流程所示。

 

查詢時(shí),先通過(guò)內(nèi)存中的btree索引來(lái)查詢?cè)搆ey對(duì)應(yīng)的keyIndex結(jié)構(gòu)體,然后再根據(jù)這個(gè)結(jié)構(gòu)體才能去boltdb中查詢真實(shí)的數(shù)據(jù)返回。

所以,下面先展開(kāi)討論這個(gè)keyIndex結(jié)構(gòu)體和btree索引。

keyIndex結(jié)構(gòu)

keyIndex結(jié)構(gòu)體有以下成員:

  • key:存儲(chǔ)數(shù)據(jù)真實(shí)的鍵。
  • modified:最后一次修改該鍵對(duì)應(yīng)的revision。
  • generations:generation數(shù)組。

如何理解generation結(jié)構(gòu)呢,可以認(rèn)為每個(gè)generation對(duì)應(yīng)一個(gè)數(shù)據(jù)從創(chuàng)建到刪除的過(guò)程。每次刪除key的操作,都會(huì)導(dǎo)致一個(gè)generation最后添加一個(gè)tombstone記錄,然后創(chuàng)建一個(gè)新的空generation記錄添加到generations數(shù)組中。

generation結(jié)構(gòu)體存放以下數(shù)據(jù):

  • ver:當(dāng)前generation中存放了多少次修改,其實(shí)就是revs數(shù)組的大小-1(因?yàn)樾枰サ魌ombstone)。
  • created:創(chuàng)建該generation時(shí)的revision。
  • revs:存放該generation中存放的revision數(shù)組。

以下圖來(lái)說(shuō)明keyIndex結(jié)構(gòu)體:

 

如上圖所示,存放的鍵為test的keyIndex結(jié)構(gòu)。

它的generations數(shù)組有兩條記錄,其中g(shù)enerations[0]在revision 1.0時(shí)創(chuàng)建,當(dāng)revision2.1的時(shí)候進(jìn)行tombstone操作,因此該generation的created是1.0;對(duì)應(yīng)的generations[1]在revision3.3時(shí)創(chuàng)建,緊跟著就做了tombstone操作。

所以該keyIndex.modifiled成員存放的是3.3,因?yàn)檫@是這條數(shù)據(jù)最后一次被修改的revision。

一個(gè)已經(jīng)被tombstone的generation是可以被刪除的,如果整個(gè)generations數(shù)組都已經(jīng)被刪除空了,那么整個(gè)keyIndex記錄也可以被刪除了。

 

如上圖所示,keyIndex.compact(n)函數(shù)可以對(duì)keyIndex數(shù)據(jù)進(jìn)行壓縮操作,將刪除滿足main revision < n的數(shù)據(jù)。

  • compact(2):找到了generations[0]的1.0 revision的數(shù)據(jù)進(jìn)行了刪除。
  • compact(3):找到了generations[0]的2.1 revision的數(shù)據(jù)進(jìn)行了刪除,此時(shí)由于generations[0]已經(jīng)沒(méi)有數(shù)據(jù)了,所以這一整個(gè)generation被刪除,原先的generations[1]變成了generations[0]。
  • compact(4):找到了generations[0]的3.3 revision的數(shù)據(jù)進(jìn)行了刪除。由于所有的generation數(shù)據(jù)都被刪除了,此時(shí)這個(gè)keyIndex數(shù)據(jù)可以刪除了。

treeIndex結(jié)構(gòu)

Etcd中使用treeIndex來(lái)在內(nèi)存中存放keyIndex數(shù)據(jù)信息,這樣就可以快速的根據(jù)輸入的key定位到對(duì)應(yīng)的keyIndex。

treeIndex使用開(kāi)源的github.com/google/btree來(lái)在內(nèi)存中存儲(chǔ)btree索引信息,因?yàn)橛玫氖峭獠繋?kù),所以不打算就這部分做解釋。而如果很清楚了前面keyIndex結(jié)構(gòu),其實(shí)這部分很好理解。

所有的操作都以key做為參數(shù)進(jìn)行操作,treeIndex使用btree根據(jù)key查找到對(duì)應(yīng)的keyIndex,再進(jìn)行相關(guān)的操作,最后重新寫入到btree中。

store

前面講到了WAL數(shù)據(jù)的存儲(chǔ)、內(nèi)存索引數(shù)據(jù)的存儲(chǔ),這部分討論持久化存儲(chǔ)數(shù)據(jù)的模塊。

etcd V3版本中,使用BoltDB來(lái)持久化存儲(chǔ)數(shù)據(jù)(etcd V2版本的實(shí)現(xiàn)不做討論)。所以這里先簡(jiǎn)單解釋一下BoltDB中的相關(guān)概念。

BoltDB相關(guān)概念

BoltDB中涉及到的幾個(gè)數(shù)據(jù)結(jié)構(gòu),分別為DB、Bucket、Tx、Cursor、Tx等。

其中:

  • DB:表示數(shù)據(jù)庫(kù),類比于Mysql。
  • Bucket:數(shù)據(jù)庫(kù)中的鍵值集合,類比于Mysql中的一張數(shù)據(jù)表。
  • 鍵值對(duì):BoltDB中實(shí)際存儲(chǔ)的數(shù)據(jù),類比于Mysql中的一行數(shù)據(jù)。
  • Cursor:迭代器,用于按順序遍歷Bucket中的鍵值對(duì)。
  • Tx:表示數(shù)據(jù)庫(kù)操作中的一次只讀或者讀寫事務(wù)。

Backend與BackendTx接口

Backend和BackendTx內(nèi)部的實(shí)現(xiàn),封裝了BoltDB,太簡(jiǎn)單就不做分析了。

Lessor接口

etcd中沒(méi)有提供針對(duì)數(shù)據(jù)設(shè)置過(guò)期時(shí)間的操作,通過(guò)租約(Lease)來(lái)實(shí)現(xiàn)數(shù)據(jù)過(guò)期的效果。而Lessor接口就提供了管理租約的相關(guān)接口。

比如,使用etcdctl命令可以創(chuàng)建一個(gè)lease:

etcdctl lease grant 10 lease 694d67ed2bfbea03 granted with TTL(10s)

這樣就創(chuàng)建了一個(gè)ID為694d67ed2bfbea03的Lease,此時(shí)可以將鍵值與這個(gè)lease進(jìn)行綁定:

etcdctl put --lease=694d67ed2bfbea03 a b

當(dāng)時(shí)間還沒(méi)超過(guò)過(guò)期時(shí)間10S時(shí),能通過(guò)etcd拿到這對(duì)鍵值的數(shù)據(jù)。如果超時(shí)了就獲取不到數(shù)據(jù)了。

從上面的命令可以看出,一個(gè)Lease可以與多個(gè)鍵值對(duì)應(yīng),由這個(gè)Lease通過(guò)管理與其綁定的鍵值數(shù)據(jù)的生命周期。

etcd中,將Lease ID存放在名為“lease”的Bucket中,注意在這里只存放Lease相關(guān)的數(shù)據(jù),其鍵值為:,之所以不存放與Lease綁定的鍵值,是因?yàn)檫@些鍵值已經(jīng)存放到另外的Bucket里了,寫入數(shù)據(jù)的時(shí)候也會(huì)將這些鍵值綁定的Lease ID寫入,這樣在恢復(fù)數(shù)據(jù)的時(shí)候就可以將鍵值與Lease ID綁定的關(guān)系寫入內(nèi)存中。

即:Lease這邊需要持久化的數(shù)據(jù)只有Lease ID與TTL值,而鍵值對(duì)這邊會(huì)持久化所綁定的Lease ID,這樣在啟動(dòng)恢復(fù)的時(shí)候可以將兩者對(duì)應(yīng)的關(guān)系恢復(fù)到內(nèi)存中。

 

明白了以上關(guān)系再來(lái)理解Lessor的實(shí)現(xiàn)就很簡(jiǎn)單了。

lessor中主要包括以下的成員:

  • leaseMap map[LeaseID]*Lease:存儲(chǔ)LeaseID與Lease實(shí)例之間的對(duì)應(yīng)關(guān)系。
  • itemMap map[LeaseItem]LeaseID:leaseItem實(shí)際存放的是鍵值,所以這個(gè)map管理的就是鍵值與Lease ID之間的對(duì)應(yīng)關(guān)系。
  • b backend.Backend:持久化存儲(chǔ),每個(gè)Lease的持久化數(shù)據(jù)會(huì)寫入名為“lease”的Bucket中。
  • minLeaseTTL int64:最小過(guò)期時(shí)間,設(shè)置給每個(gè)lease的過(guò)期時(shí)間不得小于這個(gè)數(shù)據(jù)。
  • expiredC chan []*Lease:通過(guò)這個(gè)channel通知外部有哪些Lease過(guò)期了。

其他的就很簡(jiǎn)單了:

  1. lessor啟動(dòng)之后會(huì)運(yùn)行一個(gè)goroutine協(xié)程,在這個(gè)協(xié)程里定期查詢哪些Lease超時(shí),超時(shí)的Lease將通過(guò)expiredC channel通知外部。
  2. 而針對(duì)Lease的CRUD操作,都需要進(jìn)行加鎖才能操作。

KV接口

有了以上的準(zhǔn)備,可以開(kāi)始分析數(shù)據(jù)存儲(chǔ)相關(guān)的內(nèi)容了。在etcd V3中,所有涉及到數(shù)據(jù)的存儲(chǔ),都會(huì)通過(guò)KV接口。

store結(jié)構(gòu)體實(shí)現(xiàn)了KV接口,其中最重要的就是封裝了前面提到的幾個(gè)數(shù)據(jù)結(jié)構(gòu):

  • b backend.Backend:用于將持久化數(shù)據(jù)寫入BoltDB中。
  • kvindex index:保存key索引。
  • changes []mvccpb.KeyValue:保存每次寫操作之后進(jìn)行了修改的數(shù)據(jù),用于通知watch了這些數(shù)據(jù)變更的客戶端。

在store結(jié)構(gòu)體初始化時(shí),根據(jù)傳入的backend.Backend,初始化backend.BatchTx結(jié)構(gòu),后面的任何涉及到事務(wù)的操作,都可以通過(guò)這個(gè)backend.BatchTx來(lái)進(jìn)行。

其實(shí)有了前面的準(zhǔn)備,理解store結(jié)構(gòu)做的事情已經(jīng)不難,以一次Put操作為例,其流程主要如下圖所示:

 

applierV3

EtcdServer內(nèi)部實(shí)現(xiàn)中,實(shí)際使用的是applierV3接口來(lái)進(jìn)行持久化數(shù)據(jù)的操作。

這個(gè)接口有以下幾個(gè)實(shí)現(xiàn),但是其中applierV3backend的實(shí)現(xiàn)是最重要的,其內(nèi)部使用了前面提到的KV接口來(lái)進(jìn)行數(shù)據(jù)的處理。

另外,applierV3接口還有其他幾個(gè)實(shí)現(xiàn),這里分別列舉一下。

  • applierV3backend:基礎(chǔ)的applierV3接口實(shí)現(xiàn),其他幾個(gè)實(shí)現(xiàn)都在此實(shí)現(xiàn)上做功能擴(kuò)展。內(nèi)部調(diào)用EtcdServer中的KV接口進(jìn)行持久化數(shù)據(jù)讀寫操作。
  • applierV3Capped:磁盤空間不足的情況下,EtcdServer中的applierV3切換到這個(gè)實(shí)現(xiàn)里面來(lái),這個(gè)實(shí)現(xiàn)的任何寫入操作都會(huì)失敗,這樣保證底層存儲(chǔ)的數(shù)據(jù)量不再增加。
  • authApplierV3:在applierV3backend的基礎(chǔ)上擴(kuò)展出權(quán)限控制的功能。
  • quotaApplierV3:在applierV3backend的基礎(chǔ)上加上了限流功能,即底層的存儲(chǔ)到了上限的話,會(huì)觸發(fā)限流操作。

綜述

下圖將上面涉及到的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)串聯(lián)在一起,看看EtcdServer在收到Raft庫(kù)通過(guò)Ready channel通知的可以持久化數(shù)據(jù)之后,都做了什么操作。

 

  1. raft庫(kù)通過(guò)Ready Channel通知上層的raftNode哪些數(shù)據(jù)可以進(jìn)行持久化。
  2. raftNode啟動(dòng)之后也是會(huì)啟動(dòng)一個(gè)Goroutine來(lái)一直監(jiān)聽(tīng)這個(gè)Ready Channel,以便收到可以持久化數(shù)據(jù)的通知。
  3. raftNode在收到Ready數(shù)據(jù)之后,將首先寫入WAL日志中。這里的WAL日志由storage結(jié)構(gòu)體來(lái)管理,分為兩大部分:WAL日志以及WAL快照文件數(shù)據(jù)Snapshotter,后者用來(lái)避免WAL文件一直增大。
  4. raftNode在寫WAL數(shù)據(jù)完成之后,通過(guò)apply Channel通知EtcdServer。
  5. EtcdServer啟動(dòng)之后也是啟動(dòng)一個(gè)Goroutine來(lái)監(jiān)聽(tīng)這個(gè)channel,以便收到可以持久化數(shù)據(jù)的通知。
  6. EtcdServer通過(guò)調(diào)用applierV3接口來(lái)持久化數(shù)據(jù)。applierV3backend結(jié)構(gòu)體實(shí)現(xiàn)applierV3接口, applierV3backend結(jié)構(gòu)體實(shí)現(xiàn)applierV3接口,內(nèi)部通過(guò)調(diào)用KV接口進(jìn)行持久化操作。而在實(shí)現(xiàn)KV接口的store結(jié)構(gòu)體中,treeIndex負(fù)責(zé)在內(nèi)存中維護(hù)數(shù)據(jù)鍵值與revision的對(duì)應(yīng)關(guān)系即keyIndex數(shù)據(jù),Backend接口負(fù)責(zé)持久化數(shù)據(jù),最后持久化的數(shù)據(jù)將落盤到BoltDB中。
責(zé)任編輯:武曉燕 來(lái)源: 高可用架構(gòu)
相關(guān)推薦

2019-12-16 15:39:48

Etcd存儲(chǔ)Go

2021-04-13 05:38:35

Kubernetes存儲(chǔ)數(shù)據(jù)庫(kù)

2017-10-18 08:47:53

云存儲(chǔ)技術(shù)UFile

2014-04-29 17:45:03

VMware

2018-06-07 16:33:31

大數(shù)據(jù)冷熱數(shù)據(jù)存儲(chǔ)平臺(tái)

2021-01-12 14:46:34

Kubernetes開(kāi)發(fā)存儲(chǔ)

2020-11-02 13:24:49

MySQL數(shù)據(jù)庫(kù)存儲(chǔ)

2016-09-22 09:12:26

云存儲(chǔ)實(shí)體存儲(chǔ)

2009-09-17 15:22:38

LINQ to SQL

2012-06-12 15:03:32

云存儲(chǔ)

2021-05-24 17:14:09

數(shù)字化

2020-09-17 13:15:20

騰訊云冷數(shù)據(jù)存儲(chǔ)

2011-09-05 10:39:03

Sencha Touc離線存儲(chǔ)數(shù)據(jù)庫(kù)

2017-08-03 10:13:18

對(duì)象存儲(chǔ)CIFS

2018-05-25 09:31:00

數(shù)據(jù)存儲(chǔ)高可用

2013-06-21 10:33:02

虛擬化應(yīng)用存儲(chǔ)虛擬化

2015-03-04 09:39:31

對(duì)象存儲(chǔ)系統(tǒng)Hadoop云存儲(chǔ)系統(tǒng)

2018-02-01 08:47:00

對(duì)象存儲(chǔ)服務(wù)

2017-10-12 08:59:27

企業(yè)云存儲(chǔ)架構(gòu)

2017-02-24 17:24:16

Etcd架構(gòu)分布式系統(tǒng)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 精品国产一区二区三区性色av | 欧美在线a | 夜夜摸夜夜操 | 欧产日产国产精品视频 | 亚洲国产成人av好男人在线观看 | 国产亚洲精品a | 欧美日日 | 欧美九九 | 一区二区三区在线免费观看 | 精品乱子伦一区二区三区 | 日本三级电影在线观看视频 | 国产在线一区二 | 黄色三级免费 | 国产探花在线精品一区二区 | 国产精品久久久久久久午夜片 | 成人国产精品久久 | 欧美日韩综合一区 | 欧美精品乱码久久久久久按摩 | 国产日韩欧美另类 | caoporon| 久久久久久久久精 | 日韩一二区在线观看 | 亚洲激情在线观看 | 国产精品爱久久久久久久 | 91精品国产91 | 五月天综合网 | 亚洲视频免费观看 | 日韩精品一区二区三区免费视频 | 国产女人第一次做爰毛片 | 精品欧美一区二区精品久久久 | 97色在线视频 | 欧美一区二区三区在线观看 | 天天影视综合 | 日韩精品在线一区 | av一区二区在线观看 | 欧美午夜精品 | 美女福利网站 | 精品无码久久久久国产 | 日本视频免费 | 一区二区三区小视频 | av色站|