真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

深入淺出etcd系列Part1–etcd架構(gòu)和代碼框架-創(chuàng)新互聯(lián)

1、緒論
etcd作為華為云PaaS的核心部件,實(shí)現(xiàn)了PaaS大多數(shù)組件的數(shù)據(jù)持久化、集群選舉、狀態(tài)同步等功能。如此重要的一個(gè)部件,我們只有深入地理解其架構(gòu)設(shè)計(jì)和內(nèi)部工作機(jī)制,才能更好地學(xué)習(xí)華為云Kubernetes容器技術(shù),笑傲云原生的“江湖”。本系列將從整體框架再細(xì)化到內(nèi)部流程,對(duì)etcd的代碼和設(shè)計(jì)進(jìn)行全方位解讀。本文是《深入淺出etcd》系列的第一篇,重點(diǎn)解析etcd的架構(gòu)和代碼框架,下文所用到的代碼均基于etcd v3.2.X版本。

創(chuàng)新互聯(lián)從2013年成立,先為臨縣等服務(wù)建站,臨縣等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為臨縣企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。

另,由華為云容器服務(wù)團(tuán)隊(duì)傾情打造的《云原生分布式存儲(chǔ)基石:etcd深入解析》一書已正式出版,各大平臺(tái)均有發(fā)售,購(gòu)書可了解更多關(guān)于分布式key—value存儲(chǔ)和etcd的相關(guān)內(nèi)容!

2、etcd簡(jiǎn)介
etcd是一個(gè)分布式的key-value存儲(chǔ)系統(tǒng),底層通過(guò)Raft協(xié)議進(jìn)行l(wèi)eader選舉和數(shù)據(jù)備份,對(duì)外提供高可用的數(shù)據(jù)存儲(chǔ),能有效應(yīng)對(duì)網(wǎng)絡(luò)問(wèn)題和機(jī)器故障帶來(lái)的數(shù)據(jù)丟失問(wèn)題。同時(shí)它還可以提供服務(wù)發(fā)現(xiàn)、分布式鎖、分布式數(shù)據(jù)隊(duì)列、分布式通知和協(xié)調(diào)、集群選舉等功能。為什么etcd如此重要?因?yàn)閑tcd是Kubernetes的后端唯一存儲(chǔ)實(shí)現(xiàn),毫不夸張地說(shuō),etcd就是Kubernetes的“心臟”。

2.1 Raft協(xié)議
要理解etcd分布式協(xié)同的工作原理,必須提到Raft算法。Raft算法是斯坦福的Diego Ongaro、John Ousterhout兩人以易懂(Understandability)為目標(biāo)設(shè)計(jì)的一致性共識(shí)算法。在此之前,提到共識(shí)算法(Consensus Algorithm)必然會(huì)提到Paxos,但是Paxos的實(shí)現(xiàn)和理解起來(lái)都非常復(fù)雜,以至于Raft算法提出者的博士論文中,作者提到,他們用了將近一年時(shí)間研究這個(gè)算法的各種解釋,但還是沒有完全理解這個(gè)算法。Paxos的算法原理和真正實(shí)現(xiàn)也有很大的距離,實(shí)現(xiàn)Paxos的系統(tǒng),如Chubby,對(duì)Paxos進(jìn)行了很多的改進(jìn)有優(yōu)化,但是細(xì)節(jié)卻是不為人所知的。 Raft協(xié)議采用分治的思想,把分布式協(xié)同的問(wèn)題分為3個(gè)問(wèn)題:

選舉: 一個(gè)新的集群?jiǎn)?dòng)時(shí),或者老的leader故障時(shí),會(huì)選舉出一個(gè)新的leader;

日志同步: leader必須接受客戶端的日志條目并且將他們同步到集群的所有機(jī)器;

安全: 保證任何節(jié)點(diǎn)只要在它的狀態(tài)機(jī)中生效了一條日志條目,就不會(huì)在相同的key上生效另一條日志條目。

一個(gè)Raft集群一般包含數(shù)個(gè)節(jié)點(diǎn),典型的是5個(gè),這樣可以承受其中2個(gè)節(jié)點(diǎn)故障。每個(gè)節(jié)點(diǎn)實(shí)際上就是維護(hù)一個(gè)狀態(tài)機(jī),節(jié)點(diǎn)在任何時(shí)候都處于以下三種狀態(tài)中的一個(gè)。

leader:負(fù)責(zé)日志的同步管理,處理來(lái)自客戶端的請(qǐng)求,與Follower保持這heartBeat的聯(lián)系;

follower:剛啟動(dòng)時(shí)所有節(jié)點(diǎn)為Follower狀態(tài),響應(yīng)Leader的日志同步請(qǐng)求,響應(yīng)Candidate的請(qǐng)求,把請(qǐng)求到Follower的事務(wù)轉(zhuǎn)發(fā)給Leader;

candidate:負(fù)責(zé)選舉投票,Raft剛啟動(dòng)時(shí)由一個(gè)節(jié)點(diǎn)從Follower轉(zhuǎn)為Candidate發(fā)起選舉,選舉出Leader后從Candidate轉(zhuǎn)為L(zhǎng)eader狀態(tài)。

節(jié)點(diǎn)啟動(dòng)以后,首先都是follower狀態(tài),在follower狀態(tài)下,會(huì)有一個(gè)選舉超時(shí)時(shí)間的計(jì)時(shí)器(這個(gè)時(shí)間是在配置的超時(shí)時(shí)間基礎(chǔ)上加一個(gè)隨機(jī)的時(shí)間得來(lái)的)。如果在這個(gè)時(shí)間內(nèi)沒有收到leader發(fā)送的心跳包,則節(jié)點(diǎn)狀態(tài)會(huì)變成candidate狀態(tài),也就是變成了候選人,候選人會(huì)循環(huán)廣播選舉請(qǐng)求,如果超過(guò)半數(shù)的節(jié)點(diǎn)同意選舉請(qǐng)求,則節(jié)點(diǎn)轉(zhuǎn)化為leader狀態(tài)。如果在選舉過(guò)程中,發(fā)現(xiàn)已經(jīng)有了leader或者有更高的任期值的選舉信息,則自動(dòng)變成follower狀態(tài)。處于leader狀態(tài)的節(jié)點(diǎn)如果發(fā)現(xiàn)有更高任期值的leader存在,則也是自動(dòng)變成follower狀態(tài)。

Raft把時(shí)間劃分為任期(Term)(如下圖所示),任期是一個(gè)遞增的整數(shù),一個(gè)任期是從開始選舉leader到leader失效的這段時(shí)間。有點(diǎn)類似于一屆總統(tǒng)任期,只是它的時(shí)間是不一定的,也就是說(shuō)只要leader工作狀態(tài)良好,它可能成為一個(gè)獨(dú)裁者,一直不下臺(tái)。

2.2 etcd的代碼整體架構(gòu)

從大體上可以將其劃分為以下4個(gè)模塊:

  • http:負(fù)責(zé)對(duì)外提供http訪問(wèn)接口和http client

  • raft 狀態(tài)機(jī):根據(jù)接受的raft消息進(jìn)行狀態(tài)轉(zhuǎn)移,調(diào)用各狀態(tài)下的動(dòng)作。

  • wal 日志存儲(chǔ):持久化存儲(chǔ)日志條目。

  • kv數(shù)據(jù)存儲(chǔ):kv數(shù)據(jù)的存儲(chǔ)引擎,v3支持不同的后端存儲(chǔ),當(dāng)前采用boltdb。通過(guò)boltdb支持事務(wù)操作。

相對(duì)于v2,v3的主要改動(dòng)點(diǎn)為:

  1. 使用grpc進(jìn)行peer之間和與客戶端之間通信;

  2. v2的store是在內(nèi)存中的一棵樹,v3采用抽象了一個(gè)kvstore,支持不同的后端存儲(chǔ)數(shù)據(jù)庫(kù)。增強(qiáng)了事務(wù)能力。

去除單元測(cè)試代碼,etcd v2的代碼行數(shù)約40k,v3的代碼行數(shù)約70k。

2.3 典型內(nèi)部處理流程

我們將上面架構(gòu)圖的各個(gè)部分進(jìn)行編號(hào),以便下文的處理流程介紹中,對(duì)應(yīng)找到每個(gè)流程處理的組件位置。

2.3.1 消息入口

一個(gè)etcd節(jié)點(diǎn)運(yùn)行以后,有3個(gè)通道接收外界消息,以kv數(shù)據(jù)的增刪改查請(qǐng)求處理為例,介紹這3個(gè)通道的工作機(jī)制。 1. client的http調(diào)用:會(huì)通過(guò)注冊(cè)到http模塊的keysHandler的ServeHTTP方法處理。解析好的消息調(diào)用EtcdServer的Do()方法處理。(圖中2) 2. client的grpc調(diào)用:?jiǎn)?dòng)時(shí)會(huì)向grpc server注冊(cè)quotaKVServer對(duì)象,quotaKVServer是以組合的方式增強(qiáng)了kvServer這個(gè)數(shù)據(jù)結(jié)構(gòu)。grpc消息解析完以后會(huì)調(diào)用kvServer的Range、Put、DeleteRange、Txn、Compact等方法。kvServer中包含有一個(gè)RaftKV的接口,由EtcdServer這個(gè)結(jié)構(gòu)實(shí)現(xiàn)。所以最后就是調(diào)用到EtcdServer的Range、Put、DeleteRange、Txn、Compact等方法。(圖中1) 3. 節(jié)點(diǎn)之間的grpc消息:每個(gè)EtcdServer中包含有Transport結(jié)構(gòu),Transport中會(huì)有一個(gè)peers的map,每個(gè)peer封裝了節(jié)點(diǎn)到其他某個(gè)節(jié)點(diǎn)的通信方式。包括streamReader、streamWriter等,用于消息的發(fā)送和接收。streamReader中有recvc和propc隊(duì)列,streamReader處理完接收到的消息會(huì)將消息推到這連個(gè)隊(duì)列中。由peer去處理,peer調(diào)用raftNode的Process方法處理消息。(圖中3、4)

2.3.2 EtcdServer消息處理

對(duì)于客戶端消息,調(diào)用到EtcdServer處理時(shí),一般都是先注冊(cè)一個(gè)等待隊(duì)列,調(diào)用node的Propose方法,然后用等待隊(duì)列阻塞等待消息處理完成。Propose方法會(huì)往propc隊(duì)列中推送一條MsgProp消息。 對(duì)于節(jié)點(diǎn)間的消息,raftNode的Process是直接調(diào)用node的step方法,將消息推送到node的recvc或者propc隊(duì)列中。 可以看到,外界所有消息這時(shí)候都到了node結(jié)構(gòu)中的recvc隊(duì)列或者propc隊(duì)列中。(圖中5)

2.3.3 node處理消息

node啟動(dòng)時(shí)會(huì)啟動(dòng)一個(gè)協(xié)程,處理node的各個(gè)隊(duì)列中的消息,當(dāng)然也包括recvc和propc隊(duì)列。從propc和recvc隊(duì)列中拿到消息,會(huì)調(diào)用raft對(duì)象的Step方法,raft對(duì)象封裝了raft的協(xié)議數(shù)據(jù)和操作,其對(duì)外的Step方法是真正raft協(xié)議狀態(tài)機(jī)的步進(jìn)方法。當(dāng)接收到消息以后,根據(jù)協(xié)議類型、Term字段做相應(yīng)的狀態(tài)改變處理,或者對(duì)選舉請(qǐng)求做相應(yīng)處理。對(duì)于一般的kv增刪改查數(shù)據(jù)請(qǐng)求消息,會(huì)調(diào)用內(nèi)部的step方法。內(nèi)部的step方法是一個(gè)可動(dòng)態(tài)改變的方法,將隨狀態(tài)機(jī)的狀態(tài)變化而變化。當(dāng)狀態(tài)機(jī)處于leader狀態(tài)時(shí),該方法就是stepLeader;當(dāng)狀態(tài)機(jī)處于follower狀態(tài)時(shí),該方法就是stepFollower;當(dāng)狀態(tài)機(jī)處于Candidate狀態(tài)時(shí),該方法就是stepCandidate。leader狀態(tài)會(huì)直接處理MsgProp消息。將消息中的日志條目存入本地緩存。follower則會(huì)直接將MsgProp消息轉(zhuǎn)發(fā)給leader,轉(zhuǎn)發(fā)的過(guò)程是將先將消息推送到raft的msgs數(shù)組中。 node處理完消息以后,要么生成了緩存中的日志條目,要么生成了將要發(fā)送出去的消息。緩存中的日志條目需要進(jìn)一步處理(比如同步和持久化),而消息需要進(jìn)一步處理發(fā)送出去。處理過(guò)程還是在node的這個(gè)協(xié)程中,在循環(huán)開始會(huì)調(diào)用newReady,將需要進(jìn)一步處理的日志和需要發(fā)送出去的消息,以及狀態(tài)改變信息,都封裝在一個(gè)Ready消息中。Ready消息會(huì)推行到readyc隊(duì)列中。(圖中5)

2.3.4 raftNode的處理

raftNode的start()方法另外啟動(dòng)了一個(gè)協(xié)程,處理readyc隊(duì)列(圖中6)。取出需要發(fā)送的message,調(diào)用transport的Send方法并將其發(fā)送出去(圖中4)。調(diào)用storage的Save方法持久化存儲(chǔ)日志條目或者快照(圖中9、10),更新kv緩存。 另外需要將已經(jīng)同步好的日志應(yīng)用到狀態(tài)機(jī)中,讓狀態(tài)機(jī)更新狀態(tài)和kv存儲(chǔ),通知等待請(qǐng)求完成的客戶端。因此需要將已經(jīng)確定同步好的日志、快照等信息封裝在一個(gè)apply消息中推送到applyc隊(duì)列。

2.3.5 EtcdServer的apply處理

EtcdServer會(huì)處理這個(gè)applyc隊(duì)列,會(huì)將snapshot和entries都apply到kv存儲(chǔ)中去(圖中8)。最后調(diào)用applyWait的Trigger,喚醒客戶端請(qǐng)求的等待線程,返回客戶端的請(qǐng)求。

3、重要的數(shù)據(jù)結(jié)構(gòu)

3.1 EtcdServer

type EtcdServer struct {

// 當(dāng)前正在發(fā)送的snapshot數(shù)量

inflightSnapshots int64 

//已經(jīng)apply的日志index

appliedIndex      uint64 

//已經(jīng)提交的日志index,也就是leader確認(rèn)多數(shù)成員已經(jīng)同步了的日志index

committedIndex    uint64 

//已經(jīng)持久化到kvstore的index

consistIndex consistentIndex 

//配置項(xiàng)

Cfg          *ServerConfig

//啟動(dòng)成功并注冊(cè)了自己到cluster,關(guān)閉這個(gè)通道。

readych chan struct{}

//重要的數(shù)據(jù)結(jié)果,存儲(chǔ)了raft的狀態(tài)機(jī)信息。

r       raftNode

//滿多少條日志需要進(jìn)行snapshot

snapCount uint64

//為了同步調(diào)用情況下讓調(diào)用者阻塞等待調(diào)用結(jié)果的。

w wait.Wait

//下面3個(gè)結(jié)果都是為了實(shí)現(xiàn)linearizable 讀使用的

readMu sync.RWMutex

readwaitc chan struct{}

readNotifier *notifier

//停止通道

stop chan struct{}

//停止時(shí)關(guān)閉這個(gè)通道

stopping chan struct{}

//etcd的start函數(shù)中的循環(huán)退出,會(huì)關(guān)閉這個(gè)通道

done chan struct{}

//錯(cuò)誤通道,用以傳入不可恢復(fù)的錯(cuò)誤,關(guān)閉raft狀態(tài)機(jī)。

errorc     chan error

//etcd實(shí)例id

id         types.ID

//etcd實(shí)例屬性

attributes membership.Attributes

//集群信息

cluster *membership.RaftCluster

//v2的kv存儲(chǔ)

store       store.Store

//用以snapshot

snapshotter *snap.Snapshotter

//v2的applier,用于將commited index apply到raft狀態(tài)機(jī)

applyV2 ApplierV2

//v3的applier,用于將commited index apply到raft狀態(tài)機(jī)

applyV3 applierV3

//剝?nèi)チ髓b權(quán)和配額功能的applyV3

applyV3Base applierV3

//apply的等待隊(duì)列,等待某個(gè)index的日志apply完成

applyWait   wait.WaitTime

//v3用的kv存儲(chǔ)

kv         mvcc.ConsistentWatchableKV

//v3用,作用是實(shí)現(xiàn)過(guò)期時(shí)間

lessor     lease.Lessor

//守護(hù)后端存儲(chǔ)的鎖,改變后端存儲(chǔ)和獲取后端存儲(chǔ)是使用

bemu       sync.Mutex

//后端存儲(chǔ)

be         backend.Backend

//存儲(chǔ)鑒權(quán)數(shù)據(jù)

authStore  auth.AuthStore

//存儲(chǔ)告警數(shù)據(jù)

alarmStore *alarm.AlarmStore

//當(dāng)前節(jié)點(diǎn)狀態(tài)

stats  *stats.ServerStats

//leader狀態(tài)

lstats *stats.LeaderStats

//v2用,實(shí)現(xiàn)ttl數(shù)據(jù)過(guò)期的

SyncTicker *time.Ticker

//壓縮數(shù)據(jù)的周期任務(wù)

compactor *compactor.Periodic

//用于發(fā)送遠(yuǎn)程請(qǐng)求

peerRt   http.RoundTripper

//用于生成請(qǐng)求id

reqIDGen *idutil.Generator

// forceVersionC is used to force the version monitor loop

// to detect the cluster version immediately.

forceVersionC chan struct{}

// wgMu blocks concurrent waitgroup mutation while server stopping

wgMu sync.RWMutex

// wg is used to wait for the go routines that depends on the server state

// to exit when stopping the server.

wg sync.WaitGroup

// ctx is used for etcd-initiated requests that may need to be canceled

// on etcd server shutdown.

ctx    context.Context

cancel context.CancelFunc

leadTimeMu      sync.RWMutex

leadElectedTime time.Time

}

3.2 raftNode

raftNode是Raft節(jié)點(diǎn),維護(hù)Raft狀態(tài)機(jī)的步進(jìn)和狀態(tài)遷移。

type raftNode struct {

// Cache of the latest raft index and raft term the server has seen.

// These three unit64 fields must be the first elements to keep 64-bit

// alignment for atomic access to the fields.

//狀態(tài)機(jī)當(dāng)前狀態(tài),index代表當(dāng)前已經(jīng)apply到狀態(tài)機(jī)的日志index,term是最新日志條目的term,lead是當(dāng)前的leader id

index uint64

term  uint64

lead  uint64

//包含了node、storage等重要數(shù)據(jù)結(jié)構(gòu)

raftNodeConfig

// a chan to send/receive snapshot

msgSnapC chan raftpb.Message

// a chan to send out apply

applyc chan apply

// a chan to send out readState

readStateC chan raft.ReadState

// utility

ticker *time.Ticker

// contention detectors for raft heartbeat message

td *contention.TimeoutDetector

stopped chan struct{}

done    chan struct{}

}

3.3 node

type node struct {

//Propose隊(duì)列,調(diào)用raftNode的Propose即把Propose消息塞到這個(gè)隊(duì)列里

propc      chan pb.Message

//Message隊(duì)列,除Propose消息以外其他消息塞到這個(gè)隊(duì)列里

recvc      chan pb.Message

//集群配置信息隊(duì)列,當(dāng)集群節(jié)點(diǎn)改變時(shí),需要將修改信息塞到這個(gè)隊(duì)列里

confc      chan pb.ConfChange

//外部通過(guò)這個(gè)隊(duì)列獲取修改后集群配置信息

confstatec chan pb.ConfState

//已經(jīng)準(zhǔn)備好apply的信息隊(duì)列

readyc     chan Ready

//每次apply好了以后往這個(gè)隊(duì)列里塞個(gè)空對(duì)象。通知可以繼續(xù)準(zhǔn)備Ready消息。

advancec   chan struct{}

//tick信息隊(duì)列,用于調(diào)用心跳

tickc      chan struct{}

done       chan struct{}

stop       chan struct{}

status     chan chan Status

logger Logger

}

4、小結(jié)
本文簡(jiǎn)要介紹了raft協(xié)議和etcd的框架,介紹了etcd內(nèi)部的和消息流的處理。后續(xù)將分心跳和選舉、數(shù)據(jù)同步、數(shù)據(jù)持久化等不同專題詳細(xì)講述etcd的內(nèi)部機(jī)制。

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)cdcxhl.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。


網(wǎng)頁(yè)題目:深入淺出etcd系列Part1–etcd架構(gòu)和代碼框架-創(chuàng)新互聯(lián)
文章位置:http://weahome.cn/article/hjcpj.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部