Kubernetes 之 詳解Etcd集羣

前言
html

隨着kubernetes項目的日益火熱,該項目中用到的etcd組件做爲一個高可用強一致性的服務發現存儲倉庫,漸漸的被開發人員所關注。
git

在雲計算時代,如何讓服務快速、透明的接入到計算集羣中,如何讓共享配置信息快速被集羣中的全部節點發現,如何構建一套高可用、安全、易於部署以及快速響應的服務集羣成爲了須要解決的問題。github

Etcd爲解決這類問題帶來便捷。算法

官方地址 https://coreos.com/etcd/數據庫

項目地址 https://github.com/coreos/etcdapache

image.png

Etcd是什麼api

Etcd是一個高可用的鍵值存儲系統,主要用於共享配置和服務發現,它經過Raft一致性算法處理日誌複製以保證強一致性,咱們能夠理解它爲一個高可用強一致性的服務發現存儲倉庫
安全

在kubernetes集羣中,etcd主要用於配置共享和服務發現服務器

Etcd主要解決的是分佈式系統中數據一致性的問題,而分佈式系統中的數據分爲控制數據和應用數據,etcd處理的數據類型爲控制數據,對於不多量的應用數據也能夠進行處理。網絡

Etcd和Zookeeper的比較

Zookeeper有以下缺點

  1. 1.複雜。ZooKeeper的部署維護複雜,管理員須要掌握一系列的知識和技能;而Paxos強一致性算法也是素來以複雜難懂而聞名於世(ETCD使用[Raft]協議, ZK使用ZAB,類PAXOS協議);另外,ZooKeeper的使用也比較複雜,須要安裝客戶端,官方只提供了Java和C兩種語言的接口。

  2. 2.Java編寫。這裏不是對Java有偏見,而是Java自己就偏向於重型應用,它會引入大量的依賴。而運維人員則廣泛但願保持強一致、高可用的機器集羣儘量簡單,維護起來也不易出錯。

  3. 3.發展緩慢。Apache基金會項目特有的「Apache Way」在開源界飽受爭議,其中一大緣由就是因爲基金會龐大的結構以及鬆散的管理致使項目發展緩慢。

相較之下,Etcd

      1.簡單。使用Go語言編寫部署簡單;使用HTTP做爲接口使用簡單;使用Raft算法保證強一致性讓用戶易於理解

  1. 2.數據持久化。etcd默認數據一更新就進行持久化。

  2. 3.安全。etcd支持SSL客戶端安全認證。

Etcd的架構與術語

image.png

流程分析

一般一個用戶的請求發送過來,會通過HTTP Server轉發給Store進行具體的事務處理,若是涉及到節點的修改,則須要交給Raft模塊進行狀態的變動,日誌的記錄。

而後再同步給別的etcd節點確認數據提交,最後進行數據提交,再次同步。

工做原理

Etcd使用Raft協議來維護集羣內各個節點狀態的一致性。簡單說,ETCD集羣是一個分佈式系統,由多個節點相互通訊構成總體對外服務,每一個節點都存儲了完整的數據,而且經過Raft協議保證每一個節點維護的數據是一致的。

Etcd主要分爲四個部分

  1. HTTP Server: 用於處理用戶發送的API請求以及其餘etcd節點的同步與心跳信息請求

  2. Store:  用於處理 etcd 支持的各種功能的事務,包括數據索引、節點狀態變動、監控與反饋、事件處理與執行等等,是 etcd 對用戶提供的大多數 API 功能的具體實現。

  3. Raft: Raft 強一致性算法的具體實現,是 etcd 的核心。

  4. WAL:Write Ahead Log(預寫式日誌/日誌先行),是 etcd 的數據存儲方式,也是一種實現事務日誌的標準方法。etcd經過 WAL 進行持久化存儲,全部的數據提交前都會事先記錄日誌。Snapshot 是爲了防止數據過多而進行的狀態快照;Entry 表示存儲的具體日誌內容。

服務發現

服務發現要解決的也是分佈式系統中最多見的問題之一,即在同一個分佈式集羣中的進程或服務,要如何才能找到對方並創建鏈接。本質上來講,服務發現就是想要了解集羣中是否有進程在監聽 udp 或 tcp 端口,而且經過名字就能夠查找和鏈接。要解決服務發現的問題,須要具有如下三點:

1.一個強一致性、高可用的服務存儲目錄。基於 Raft 算法的 etcd 天生就是這樣一個強一致性高可用的服務存儲目錄。

2.一種註冊服務和監控服務健康狀態的機制。用戶能夠在 etcd 中註冊服務,而且對註冊的服務設置key TTL,定時保持服務的心跳以達到監控健康狀態的效果。

3.一種查找和鏈接服務的機制。經過在 etcd 指定的主題下注冊的服務也能在對應的主題下查找到。爲了確保鏈接,咱們能夠在每一個服務機器上都部署一個 Proxy 模式的 etcd,這樣就能夠確保能訪問 etcd 集羣的服務都能互相鏈接。
例如隨着 Docker 容器的流行,多種微服務共同協做,構成一個相對功能強大的架構的案例愈來愈多。透明化的動態添加這些服務的需求也日益強烈。經過服務發現機制,在 etcd 中註冊某個服務名字的目錄,在該目錄下存儲可用的服務節點的 IP。在使用服務的過程當中,只要從服務目錄下查找可用的服務節點去使用便可。

Etcd集羣中的術語

  • Raft: etcd所採用的保證分佈式系統強一致的算法

  • Node: 一個Raft狀態機實例

  • Member: 一個etcd實例,管理一個Node,能夠爲客戶端請求提供服務

  • Cluster: 多個Member構成的能夠協同工做的etcd集羣

  • Peer: 同一個集羣中,其餘Member的稱呼

  • Client: 向etcd集羣發送HTTP請求的客戶端

  • WAL: 預寫日誌,是etcd用於持久化存儲的日誌格式

  • Snapshot: etcd防止WAL文件過多而設置的快照,存儲etcd數據狀態

  • Proxy: etcd的一種模式,能夠爲etcd提供反向代理服務

  • Leader: Raft算法中經過競選而產生的處理全部數據提交的節點

  • Follower: Raft算法中競選失敗的節點,做爲從屬節點,爲算法提供強一致性保證

  • Candidate: Follower超過必定時間接收不到Leader節點的心跳的時候,會轉變爲Candidate(候選者)開始Leader競選

  • Term: 某個節點稱爲Leader到下一次競選開始的時間週期,稱爲Term(任界,任期)

  • Index: 數據項編號, Raft中經過Term和Index來定位數據

Raft算法

Raft 是一種爲了管理複製日誌的一致性算法。它提供了和 Paxos 算法相同的功能和性能,可是它的算法結構和 Paxos 不一樣,使得 Raft 算法更加容易理解而且更容易構建實際的系統。一致性算法容許一組機器像一個總體同樣工做,即便其中一些機器出現故障也可以繼續工做下去。正由於如此,一致性算法在構建可信賴的大規模軟件系統中扮演着重要的角色。

Raft算法分爲三部分

Leader選舉、日誌複製和安全性

Raft算法特性:

1.強領導者: 和其餘一致性算法相比,Raft 使用一種更強的領導能力形式。好比,日誌條目只從領導者發送給其餘的服務器。這種方式簡化了對複製日誌的管理而且使得 Raft 算法更加易於理解。

2.領導選舉: Raft 算法使用一個隨機計時器來選舉領導者。這種方式只是在任何一致性算法都必須實現的心跳機制上增長了一點機制。在解決衝突的時候會更加簡單快捷。

3.成員關係調整: Raft 使用一種共同一致的方法來處理集羣成員變換的問題,在這種方法下,處於調整過程當中的兩種不一樣的配置集羣中大多數機器會有重疊,這就使得集羣在成員變換的時候依然能夠繼續工做。

Leader選舉

Raft 狀態機

Raft集羣中的每一個節點都處於一種基於角色的狀態機中。具體來講,Raft定義了節點的三種角色: Follower、Candidate和Leader。

1.Leader(領導者): Leader節點在集羣中有且僅能有一個,它負責向全部的Follower節點同步日誌數據

2.Follower(跟隨者): Follower節點從Leader節點獲取日誌,提供數據查詢功能,並將全部修改請求轉發給Leader節點

3.Candidate(候選者): 當集羣中的Leader節點不存在或者失聯以後,其餘Follower節點轉換爲Candidate,而後開始新的Leader節點選舉

這三種角色狀態之間的轉換,以下圖:

image.png

 一個 Raft 集羣包含若干個服務器節點;一般是 5 個,這容許整個系統容忍 2 個節點的失效。在任什麼時候刻個服務器節點都處於這三個狀態之一:領導人、跟隨者或者候選人。在一般狀況下,系統中只有一個領導人而且其餘的節點所有都是跟隨者。跟隨者都是被動的:他們不會發送任何請求,只是簡單的響應來自領導者或者候選人的請求。領導人處理全部的客戶端請求(若是一個客戶端和跟隨者聯繫,那麼跟隨者會把請求重定向給領導人)

在節點初始啓動的時候,全部節點的Raft狀態機都會處於Follower狀態。當Follower在必定的時間週期內沒有收到來自Leader節點的心跳數據包的時候,節點會將本身的狀態切換爲Candidate,並向集羣中其餘Follower節點發送投票請求,Follower都會將本身的票投給收到的第一個投票請求節點。當Candidate收到來自集羣中超過半數節點的投票後,會成爲新的Leader節點。

Leader節點將接受並保存用戶發送的數據,並向其餘的Follower節點同步日誌。

Follower只響應來自其餘服務器的請求。若是Follower接收不到消息,那麼他就會變成候選人併發起一次選舉。得到集羣中大多數選票的候選人將成爲Leader。在一個任期(Term)內,領導人一直都會是領導人直到本身宕機了。

Leader節點依靠定時向全部Follower發送心跳數據來保持地位。當急羣衆的Leader節點出現故障的時候,Follower會從新選舉新的節點,保證整個集羣正常運行。 

每次成功的選舉,新的Leader的Term(任期)值都會比以前的Leader增長1。當集羣中因爲網絡或者其餘緣由出現分裂後又從新合併的時候,集羣中可能會出現多於一個的Leader節點,此時,Term值更高的節點纔會成爲真正的Leader。

Raft算法中的Term(任期)

關於Term,以下圖:

image.png

Raft會把時間分割成任意長度的任期。而且任期用連續的整數來標記。每一段任期都是從一次選舉開始一個或者多個候選人嘗試成爲領導者。若是一個候選人贏得選舉,而後他就會在接下來的任期中充當Leader的職責。在某些狀況下,一次選舉會形成選票瓜分,這樣,這一個任期將沒有Leader。若是沒有Leader,那麼新的一輪選舉就立刻開始,也就是新的任期就會開始。Raft保證了在一個Term任期內,有且只有一個Leader。

日誌複製

所謂日誌複製,是指主節點將每次操做造成日誌條目,並持久化到本地磁盤,而後經過網絡IO發送給其餘節點。

一旦一個領導人被選舉出來,他就開始爲客戶端提供服務。客戶端的每個請求都包含一條被複制狀態機執行的指令領導人把這條指令做爲一條新的日誌條目附加到日誌中去,而後並行的發起附加條目 RPCs 給其餘的服務器,讓他們複製這條日誌條目。

Raft 算法保證全部已提交的日誌條目都是持久化的而且最終會被全部可用的狀態機執行。當主節點收到包括本身在內超過半數節點成功返回,那麼認爲該日誌是可提交的(committed),並將日誌輸入到狀態機,將結果返回給客戶端。

在正常的操做中,領導人和跟隨者的日誌保持一致性,因此附加日誌 RPC 的一致性檢查歷來不會失敗。然而,領導人崩潰的狀況會使得日誌處於不一致的狀態(老的領導人可能尚未徹底複製全部的日誌條目)。這種不一致問題會在一系列的領導人和跟隨者崩潰的狀況下加重。跟隨者的日誌可能和新的領導人不一樣的方式。跟隨者可能會丟失一些在新的領導人中有的日誌條目,他也可能擁有一些領導人沒有的日誌條目,或者二者都發生。丟失或者多出日誌條目可能會持續多個任期。這就引出了另外一個部分,就是安全性

安全性

截止此刻,選主以及日誌複製並不能保證節點間數據一致。試想,當一個某個節點掛掉了,一段時間後再次重啓,並當選爲主節點。而在其掛掉這段時間內,集羣如有超過半數節點存活,集羣會正常工做,那麼會有日誌提交。這些提交的日誌沒法傳遞給掛掉的節點。當掛掉的節點再次當選主節點,它將缺失部分已提交的日誌。在這樣場景下,按Raft協議,它將本身日誌複製給其餘節點,會將集羣已經提交的日誌給覆蓋掉。這顯然是錯誤的

其餘協議解決這個問題的辦法是,新當選的主節點會詢問其餘節點,和本身數據對比,肯定出集羣已提交數據,而後將缺失的數據同步過來。這個方案有明顯缺陷,增長了集羣恢復服務的時間(集羣在選舉階段不可服務),而且增長了協議的複雜度。Raft解決的辦法是,在選主邏輯中,對可以成爲主的節點加以限制,確保選出的節點已定包含了集羣已經提交的全部日誌。若是新選出的主節點已經包含了集羣全部提交的日誌,那就不須要從和其餘節點比對數據了。簡化了流程,縮短了集羣恢復服務的時間。

這裏存在一個問題,加以這樣限制以後,還可否選出主呢?答案是:只要仍然有超過半數節點存活,這樣的主必定可以選出。由於已經提交的日誌必然被集羣中超過半數節點持久化,顯然前一個主節點提交的最後一條日誌也被集羣中大部分節點持久化。當主節點掛掉後,集羣中仍有大部分節點存活,那這存活的節點中必定存在一個節點包含了已經提交的日誌了。

Etcd的代理節點(proxy)

Etcd針對Raft的角色模型進行了擴展,增長了Proxy角色proxy模式的本職就是啓一個HTTP代理服務器把客戶發到這個服務器的請求轉發給別的 etcd 節點。

做爲Proxy角色的節點不會參與Leader的選舉,只是將全部接收到的用戶查詢和修改請求轉發到任意一個Follower或者Leader節點上。

Proxy節點能夠在啓動Etcd的時候經過"--proxy on"參數指定。在使用了"節點自發現"服務的集羣中,能夠設置一個固定的"參選節點數目",超過這個數目的成員自動轉換爲Proxy節點。

一旦節點成爲Proxy以後,便再也不參與全部Leader選舉和Raft狀態變化。除非將這個節點重啓並指定爲成員的Follower節點

etcd 做爲一個反向代理把客戶的請求轉發給可用的 etcd 集羣。這樣,你就能夠在每一臺機器都部署一個 Proxy 模式的 etcd 做爲本地服務,若是這些 etcd Proxy 都能正常運行,那麼你的服務發現必然是穩定可靠的。

完整的Etcd角色狀態轉換過程以下圖:

image.png

kubernetes項目中,Etcd用來作什麼,爲何選擇它

etcd在kubernetes集羣是用來存放數據並通知變更的

Kubernetes中沒有用到數據庫,它把關鍵數據都存放在etcd中,這使kubernetes的總體結構變得很是簡單。

在kubernetes中,數據是隨時發生變化的,好比說用戶提交了新任務、增長了新的Node、Node宕機了、容器死掉了等等,都會觸發狀態數據的變動。狀態數據變動以後呢,Master上的kube-scheduler和kube-controller-manager,就會從新安排工做,它們的工做安排結果也是數據。這些變化,都須要及時地通知給每個組件。etcd有一個特別好用的特性,能夠調用它的api監聽其中的數據,一旦數據發生變化了,就會收到通知。有了這個特性以後,kubernetes中的每一個組件只須要監聽etcd中數據,就能夠知道本身應該作什麼。kube-scheduler和kube-controller-manager呢,也只須要把最新的工做安排寫入到etcd中就能夠了,不用本身費心去逐個通知了

試想一下,若是沒有etcd,那麼要怎樣作?這裏的本質是:數據的傳遞有兩種方式,一種是消息的方式,好比說NodeA有了新的任務,Master直接給NodeA發一個消息,中間不通過任何人;一種是輪詢的方式,你們都把數據寫到同一個地方,每一個人自覺地盯着看,及時發現變化。前者演化出rabbitmq這樣的消息隊列系統,後者演化出一些有訂閱功能的分佈式系統。

第一種方式的問題是,全部要通訊的組件之間都要創建長鏈接,而且要處理各類異常狀況,比例如鏈接斷開、數據發送失敗等。不過有了消息隊列(message queue)這樣的中間件以後,問題就簡單多了,組件都和mq創建鏈接便可,將各類異常狀況都在mq中處理。

那麼爲何kubernetes沒有選用mq而是選用etcd呢?mq和etcd是本質上徹底不一樣的系統,mq的做用消息傳遞,不儲存數據(消息積壓不算儲存,由於沒有查詢的功能,etcd是個分佈式存儲(它的設計目標是分佈式鎖,順帶有了存儲功能),是一個帶有訂閱功能的key-value存儲。若是使用mq,那麼還須要引入數據庫,在數據庫中存放狀態數據。

選擇etcd還有一個好處,etcd使用raft協議實現一致性,它是一個分佈式鎖,能夠用來作選舉。若是在kubernetes中部署了多個kube-schdeuler,那麼同一時刻只能有一個kube-scheduler在工做,不然各自安排各自的工做,就亂套了。怎樣保證只有一個kube-schduler在工做呢?那就是前文說到的經過etcd選舉出一個leader

相關文章
相關標籤/搜索