溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

wal怎么實(shí)現(xiàn)日志讀寫(xiě)

發(fā)布時(shí)間:2021-12-18 15:36:08 來(lái)源:億速云 閱讀:249 作者:iii 欄目:云計(jì)算

這篇文章主要介紹“wal怎么實(shí)現(xiàn)日志讀寫(xiě)”,在日常操作中,相信很多人在wal怎么實(shí)現(xiàn)日志讀寫(xiě)問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”wal怎么實(shí)現(xiàn)日志讀寫(xiě)”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

etcd raft介紹

etcd raft是目前使用最廣泛的raft庫(kù), etcd raft在etcd, Kubernetes, Docker Swarm, Cloud Foundry Diego, CockroachDB, TiDB, Project Calico, Flannel等分布式系統(tǒng)中都有應(yīng)用,在生成環(huán)境得到了驗(yàn)證。 傳統(tǒng)raft庫(kù)的實(shí)現(xiàn)都是單體設(shè)計(jì)(集成了存儲(chǔ)層、消息序列化、網(wǎng)絡(luò)層等), etcd raft繼承了簡(jiǎn)約的設(shè)計(jì)理念,只實(shí)現(xiàn)了最核心的raft算法, 這樣更加的靈活。etcd將網(wǎng)絡(luò)、日志存儲(chǔ)、快照等功能分開(kāi),通過(guò)獨(dú)立的模塊實(shí)現(xiàn),用戶(hù)可以在需要時(shí)調(diào)用。etcd自身實(shí)現(xiàn)了自己的一套raft配套庫(kù):etcd-wal(用于存儲(chǔ)日志),snap(用于存儲(chǔ)快照),MemoryStorage(用于存儲(chǔ)當(dāng)前日志、快照、狀態(tài)等信息以供raft核心程序使用)。

wal怎么實(shí)現(xiàn)日志讀寫(xiě)

etcd wal介紹

WAL是write ahead log的縮寫(xiě),etcd使用wal模塊來(lái)完成raft日志的持久化存儲(chǔ),etcd對(duì)wal的所有實(shí)現(xiàn)都放在wal目錄中。

wal數(shù)據(jù)結(jié)構(gòu)

type WAL struct {
lg *zap.Logger

dir string // the living directory of the underlay files

// dirFile is a fd for the wal directory for syncing on Rename
dirFile *os.File

metadata []byte // metadata recorded at the head of each WAL
state raftpb.HardState // hardstate recorded at the head of WAL

start walpb.Snapshot // snapshot to start reading
decoder *decoder // decoder to decode records
readClose func() error // closer for decode reader

mu sync.Mutex
enti uint64 // index of the last entry saved to the wal
encoder *encoder // encoder to encode records

locks []*fileutil.LockedFile // the locked files the WAL holds (the name is increasing)
fp *filePipeline
}

上述為wal的數(shù)據(jù)結(jié)構(gòu),通過(guò)用wal.go文件中的Create()方法來(lái)獲取wal的實(shí)例。wal首先會(huì)創(chuàng)建一個(gè)臨時(shí)目錄并初始化相關(guān)變量,并創(chuàng)建和初始化第一個(gè)wal文件,等所有的操作都初始化完成后直接更改臨時(shí)目錄的名字完成wal實(shí)例的初始化。

文件組織

wal的所有日志放在一個(gè)指定目錄下,日志的文件名以 .wal 作為結(jié)尾,格式為-.wal,seq和index的格式都為%016x,例如:0000000000000001-0000000000000001.wal。index代表這個(gè)文件中第一條raft日志的index,seq是這個(gè)文件的序列號(hào)(依次遞增)。

每個(gè)文件的大小默認(rèn)為64M,當(dāng)文件大于64M時(shí),wal會(huì)自動(dòng)生成新的日志文件用于存儲(chǔ)日志。每個(gè)日志文件都會(huì)使用flock鎖定文件,參數(shù)為L(zhǎng)OCK_EX,這是一把獨(dú)有鎖,同一時(shí)間只能有一個(gè)進(jìn)程可以操作這個(gè)日志文件,所以當(dāng)wal占有這個(gè)文件時(shí),通過(guò)進(jìn)程是無(wú)法刪除這個(gè)文件的。

日志邏輯組織

wal日志可以存儲(chǔ)多種類(lèi)型的數(shù)據(jù),具體如下。

wal怎么實(shí)現(xiàn)日志讀寫(xiě)

wal怎么實(shí)現(xiàn)日志讀寫(xiě)

  • crcType 每個(gè)新的日志文件的第一條記錄都會(huì)是crcType類(lèi)型的記錄,crcType也只會(huì)在每個(gè)日志文件的開(kāi)始時(shí)寫(xiě)入,用于記錄上一個(gè)文件最后的crc是多少

  • metadataType 每個(gè)新的日志文件中metadataType緊跟在crcType記錄后面,每個(gè)日志文件只會(huì)出現(xiàn)一次

  • stateType 這種日志類(lèi)型會(huì)在兩種情況下加入:

  1. 自動(dòng)切分日志文件時(shí),新的日志文件中,緊跟在metadataType后面會(huì)存入一條stateType的日志

  2. 當(dāng)raft核心程序ready中返回hard state時(shí)也會(huì)存儲(chǔ)該類(lèi)型的日志

  • snapshotType wal日志中只會(huì)存儲(chǔ)snapshot的term和index,具體的數(shù)據(jù)存儲(chǔ)在專(zhuān)門(mén)的snapshot中,每次存儲(chǔ)快照都會(huì)在wal日志中存儲(chǔ)一個(gè)wal的快照。當(dāng)存儲(chǔ)快照時(shí),會(huì)將快照之前index的日志文件都釋放掉。wal中存儲(chǔ)的snapshot主要用于檢查快照是否正確。

日志讀寫(xiě)

wal通過(guò)封裝的encoder和decoder模塊來(lái)實(shí)現(xiàn)日志讀寫(xiě)。

寫(xiě)日志

encoder模塊把會(huì)增量的計(jì)算crc和數(shù)據(jù)一起寫(xiě)入到wal文件中。 下面為encoder數(shù)據(jù)結(jié)構(gòu)

type encoder struct {
mu sync.Mutex
bw *ioutil.PageWriter

crc hash.Hash42
buf []byte //緩存空間,默認(rèn)為1M,降低數(shù)據(jù)分配的壓力
uint64buf []byte
}

wal通過(guò)encoder實(shí)現(xiàn)寫(xiě)日志,在這個(gè)模塊中會(huì)完成crc的計(jì)算。wal為了更好的管理數(shù)據(jù),日志中的每條數(shù)據(jù)都會(huì)以8字節(jié)對(duì)齊(wal會(huì)自動(dòng)對(duì)齊字節(jié))。 日志寫(xiě)入的流程如下。

wal怎么實(shí)現(xiàn)日志讀寫(xiě)

圖中的crc是增量計(jì)算,以之前的所有日志數(shù)據(jù)為增量基礎(chǔ)。 wal只關(guān)注寫(xiě)入日志,不會(huì)校驗(yàn)日志的index是否重復(fù),但是如果重啟這個(gè)Node的話,系統(tǒng)會(huì)自動(dòng)過(guò)濾掉中間混雜的日志。

日志切分

wal實(shí)現(xiàn)了日志自動(dòng)切分,當(dāng)日志數(shù)據(jù)大于默認(rèn)的64M時(shí)就會(huì)生成新的文件寫(xiě)入日志,日志的切分通過(guò)wal.go文件中的cut方法來(lái)實(shí)現(xiàn)。cut方法只會(huì)在調(diào)用wal中的Save方法才會(huì)觸發(fā)調(diào)用,新文件的第一條記錄就是上一個(gè)wal文件最后的crc。

日志compact

wal沒(méi)有實(shí)現(xiàn)日志的自動(dòng)compact,系統(tǒng)只提供了MemoryStorage的日志compact方法(需要用戶(hù)主動(dòng)調(diào)用)。

file_pipeline模塊

wal新建新的文件時(shí)都是先新建一個(gè)tmp文件,當(dāng)所有操作都完成后再重命名這個(gè)文件。wal使用file_pipeline這個(gè)模塊在后臺(tái)啟動(dòng)一個(gè)協(xié)程時(shí)刻準(zhǔn)備一個(gè)臨時(shí)文件以供使用,從而避免臨時(shí)創(chuàng)建文件的開(kāi)銷(xiāo)。

etcd snap介紹

etcd raft自帶了go.etcd.io/etcd/etcdserver/api/snap模塊來(lái)實(shí)現(xiàn)快照的存儲(chǔ)。

文件組織

在snap模塊中一個(gè)快照用一個(gè)后綴名為.snap的文件存儲(chǔ),文件格式為-.snap, term和index分別代表快照日志所處的term和index。 每個(gè)快照具體存儲(chǔ)結(jié)構(gòu)如下圖:

wal怎么實(shí)現(xiàn)日志讀寫(xiě)

詳細(xì)介紹

系統(tǒng)可以有多個(gè)快照,snap模塊使用Snapshotter結(jié)構(gòu)統(tǒng)一管理快照。

type Snapshotter struct {
lg *zap.Logger
dir string
}

上面snapshotter的結(jié)構(gòu)代碼,snapshotter主要用于存儲(chǔ)和讀取快照。

快照具體存儲(chǔ)的內(nèi)容需要用戶(hù)來(lái)指定,例如在raft的官方例子中直接將當(dāng)時(shí)的kv數(shù)據(jù)Marshal之后存儲(chǔ)到快照中。

func (s *kvstore) getSnapshot() ([]byte, error) {
s.mu.RLock()
defer s.mu.RUnlock()
return json.Marshal(s.kvStore)
}

何時(shí)打快照

在etcd-raft中用戶(hù)可以選擇何時(shí)打快照,在etcd的官方案例中打快照的方法是maybeTriggerSnapshot(),這個(gè)方法在節(jié)點(diǎn)的Ready()方法返回時(shí)調(diào)用,當(dāng)前提交的index值與上一次大快照的index值大于10000時(shí)會(huì)打新的快照。

etcd MemoryStorage介紹

MemoryStorage用于存儲(chǔ)raft節(jié)點(diǎn)臨時(shí)的數(shù)據(jù),包括entrys、快照等。用戶(hù)將數(shù)據(jù)存儲(chǔ)到memoryStorage中,raft節(jié)點(diǎn)也會(huì)使用這些數(shù)據(jù)。包括entrys的傳遞、快照的發(fā)送等都是從memoryStorage中發(fā)送。

// MemoryStorage implements the Storage interface backed by an
// in-memory array.
type MemoryStorage struct {
// Protects access to all fields. Most methods of MemoryStorage are
// run on the raft goroutine, but Append() is run on an application
// goroutine.
sync.Mutex

hardState pb.HardState
snapshot pb.Snapshot
// ents[i] has raft log position i+snapshot.Metadata.Index
ents []pb.Entry
}

memoryStorage會(huì)存儲(chǔ)最新的entrys(包括哪些沒(méi)有commit)、快照和狀態(tài),用戶(hù)在收到其它節(jié)點(diǎn)發(fā)送的相關(guān)數(shù)據(jù)時(shí)需要將數(shù)據(jù)存儲(chǔ)到memorystorage中。

    到此,關(guān)于“wal怎么實(shí)現(xiàn)日志讀寫(xiě)”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

    向AI問(wèn)一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    wal
    AI