天天看點

etcd版本之v3系列文章目錄

系列文章目錄

淺談分布式系統與一緻性協定(一)

淺談分布式系統與一緻性協定(二)

淺談分布式系統與一緻性協定(三)

深入淺出之etcd

深入淺出之etcd(二)

etcd版本之v3

etcd之安全性闡述

etcd的多版本并發控制

概述

etcd v3存儲的資料通過KV API對外暴露,并在API的層級支援mini事務。并且為了保證向後相容,保留了etcd v2的協定與API。也就是說etcd v2和etcd v3本質上是共享一套Raft協定代碼的,差別是API不同,存儲不同,資料互相隔離。v2的資料隻能通過v2的API通路,v3的資料隻能通過v3的API通路。

etcd v2 到 etcd v3

etcd廣泛應用到分布式網絡,服務發現,配置中心,分布式系統排程和負載均衡領域。etcd專注于key-value存儲而不是完整的資料庫,通過HTTP+JSON的方式暴露給外部API,watch機制提供持續監聽某個key變化的功能,基于TTL的key自動過期機制,這些特性很好的滿足了etcd的初步需求。但是,也出現了一些問題,用戶端需要頻繁的與服務端進行通信,叢集即使在空閑時間也需要承受很大的壓力,垃圾回收key的時間不穩定。是以,etcd v3借鑒了etcd v2的經驗,做出了如下優化:

  • 使用gRPC+protobuf取代HTTP+JSON通信,提高通信效率,另外,通過gRPC gateway來繼續保持對HTTP JSON接口的支援
  • 使用lease(租約)的key自動過期機制,取代了TTL的key自動過期機制 watcher機制進行優化,基于HTTP/2的server push,并且對時間進行了多路複用優化
  • etcd v3資料模型改變,v2版本的etcd是一個簡單的kv記憶體資料庫,而etcd v3是一個支援事務和多版本并發控制的磁盤資料庫。etcd v2資料不直接落盤,落盤的日志和快照檔案隻是資料的中間格式而非最終形式,系統通過回放日志檔案來建構資料的最終形式。etcd v3落盤是資料的最終形式,日志和快照檔案的主要作用是分布式的複制

gRPC

gRPC是一個高性能,跨語言的RPC架構,基于HTTP/2協定實作。使用protobuf作為序列化和反序列化協定,即基于protobuf來聲明資料模型和RPC接口服務

序列化和反序列化優化

protobuf效率高,遠高于JSON,etcd v3的gRPC序列化和反序列化的速度是etcd v2的兩倍多

減少了TCP連接配接

etcd v2的通信協定使用HTTP/1.1,gRPC支援HTTP/2,HTTP/2對HTTP通信進行多路複用,可以共享一個TCP連接配接。是以etcd v3大大減少了用戶端與服務端的連接配接數,一個用戶端與服務端建立一個TCP連接配接,而etcd v2,一個用戶端需要與服務端建立多個連接配接,每個HTTP請求都需要建立連接配接

租約機制

etcd v2的key自動過期是基于TTL的,用戶端可以為一個key設定自動過期時間,一旦TTL到了。服務端就自動删除該key。如果用戶端不想服務端删除某個key,就需要定期更新這個key的TTL。也就是說即使整個叢集都處于空閑狀态,也會也很多用戶端需要與伺服器進行定期通信,以保證某個key不會自動被删除。而且TTL都是設定在key上,那麼對于用戶端想保留每個key,用戶端需要對每個key進行定期更新,即使這些key的過期時間都是一樣的

etcd v3使用(lease)租約機制,替代了基于TTL的自動過期機制。使用者建立一個lease,然後将這個租約與key關聯起來。一旦租約過期,etcd v3服務端就會删除與這個租約關聯的所有的key。即,多個key的過期時間是一樣的,這些key可以共享一個租約。這樣減少了用戶端請求的數量,對于共享一個租約的key,用戶端隻需要更新這個租約的過期時間即可,不需要更新所有的key

etcd v3 的watch機制

watch機制使得用戶端可以監控一個key的變化,當key發生變化時,服務端将通知用戶端,而不是讓用戶端定期向伺服器發送請求去輪詢key的變化。etcd v2的服務端對每個用戶端的每個watch請求都維持着一個HTTP長連接配接,如果數千個用戶端watch數千個key,那麼etcd v2服務端的socket和記憶體資源會很快消耗掉。

etcd v3對同一個用戶端的watch請求進行多路複用,這樣的化,同一個用戶端隻需要與服務端維護一個TCP連接配接即可,這樣大大減少了服務端壓力

etcd v2的每個watcher都會占用一個TCP資源和一個goroutine資源,大概消耗30~40kb。etcd v3減少每個Watcher帶來的資源消耗以此支援了大規模的watch,同樣的使用者不同的watcher隻消耗一個go routine,這樣再一次減輕了伺服器資源的消耗

etcd v3的資料存儲模型

etcd 時一個key-value資料庫,etcd v2隻儲存key的最新的value,之前的value直接覆寫掉了。但是etcd v2維護了一個全局的key例是記錄變更視窗,預設儲存最新的1000個變更,。etcd v2隻儲存1000個曆史變更,這樣帶來的後果是watch丢失事件。etcd v3抛棄了這種設計,引入了MVCC(多版本并發控制),采用了曆史紀錄為主索引的存儲結構,儲存了key的所有變更記錄。etcd v3可以存儲十萬個曆史記錄進行快速查詢,并且更具使用者要求進行壓縮合并。由于etcd v3實作了MVCC,記錄了所有的曆史記錄,是以這些資料不能都放在記憶體中。是以,etcd v3是一個磁盤資料庫,底層的存儲引擎使用BoltDB

etcd v3的迷你事務

很多情況下,用戶端需要同時去讀或者寫一個key,或者很多個key。提供同步原語防止資料競争是重要的。etcd v3中引入了迷你事務(mini-transaction)的概念。每個迷你事務都可以包含一些列條件語句,隻有在滿足特定條件下事務才會執行。迷你事務支援原子的比較多個鍵值并且操作多個鍵值。之前CAS是特殊的針對單個key的迷你事務。

gRPC服務

發送至etcd v3伺服器的每一個API請求均為gRPC遠端過程調用。etcd v3将其歸類為不同的服務(service),而service又可分為方法(method)定義和消息(message)定義。

根據etcd v3的所定義的不同服務,其API可以分為鍵值(KV),叢集(Cluster),維護(Maintenance),認證/鑒權(Auth),觀察(Watch)與租約(Lease)六大類

各類服務所包含的方法具體描述了與其對應的API所具備的功能,從大的角度概括,這些服務又可以分為兩類,其中一類是管理叢集的API,具體包括如下功能:

  • Auth

    Service可能是某項鑒定過程以及處理鑒定的請求,比如,增加或者删除使用者,更改使用者密碼,查詢使用者資訊和擷取使用者清單,以及授權或者撤銷使用者角色,增加或者删除角色,查詢角色資訊和擷取角色清單,以及為角色授予或撤銷某項特定的key

  • Cluster Service用于在叢集中增加或删除成員,更新成員配置,以及得到叢集中包含所有成員的清單
  • Maintenance Service則提供了啟動或者停止警報以及查詢警報的功能,還可以查詢成員的狀态資訊,為成員後端資料庫整理碎片,在client的流中發送某成員的完整後端快照

另外一大類是處理etcd鍵值空間的API,具體包括如下:

  • KV Service:用于建立,更新,擷取以及删除鍵值對
  • Watch Service:用于監聽key的變化
  • Lease Service:用于消耗用戶端keep-alive消息的原語

請求和響應

etcd v3的所有RPC都遵循相同得格式。每個RPC都形如一個函數聲明,都有一個入參和傳回值。

etcd v3 API的所有響應都攜帶一個響應頭部,包含了etcd叢集的中繼資料。示例代碼如下:

message ResponseHeader {
	 uint64ccluster_id = 1 ;
	 uint64 member_id = 2 ;
	 int64 revision = 3;
	 uint64 raft_term = 4;
 }
           

上述代碼字段說明如下:

  • cluster_id:生成響應的cluster ID
  • member_id:生成該相應的member ID
  • revision:生成該響應的鍵值存儲的版本。修改etcd背景鍵值存儲的每一步操作都會被賦予一個單調遞增的版本号(revision)。一個事物可能修改多次背景鍵值存儲,但隻會産生一個revision。被操作修改的鍵值對的revision屬性與操作的revision具有相同的值。revision可以用作背景鍵值存儲的邏輯鎖。擁有更大revision值的鍵值對肯定是revision值較小的鍵值對之後被修改,兩個revision相同的鍵值對肯定被某個操作(一般是事務)同時修改
  • Raft_Term:生成該響應的member所處的Raft協定任期(term)

    用戶端可以通過檢查Cluster_ID或者Member_ID子段的值來确認是否正在與目标叢集或節點通信

用戶端可以通過revision的值擷取發生該操作時,etcd叢集後端鍵值存儲最新revision。用戶端可以通過Rafr_Term的值來檢測etcd叢集是否完成了一次新的上司人選舉

KV API

鍵值對(key-value pair)是KV API所能處理的最小機關,每個鍵值對均包含一些protobuf格式的子段

message  KetValue {
 bytes key = 1;
 bytes value = 2;
 int64 create_revision = 3;
 int64 mod_revision = 4;
 int64 version = 5 ;
 int64 lease = ;
 } 
           

從上面定義可以看出,在KV message中,除了key-value映射值及其lease資訊之外,還有一類重要的revsiosn中繼資料(包括create_revision和mod_revsion)。這些revsion資訊可以根據建立時間和修改時間對key進行排序

revision

etcd 的revision本質上就是etcd維護的一個在叢集範圍有效的64位計數器。隻要etcd的鍵空間發生變化,ervision值也會行吟閣增加。也可以jiangrevision看成是全局的邏輯時鐘,即所有針對後端存儲的修改操作進行連續的排序。revision的值是單調遞增的,而與某個revision相關聯的資料則是那些改變了後端存儲的資料。從内部實作來看,出現一個revision,就意味着某些修改寫入了後端的B+樹,而這些修改柴采用增大的revision作為索引

對于etcd v3的多版本并發控制,revision價值不言而喻。MVCC模型是指由于儲存了鍵空間的曆史,是以可以檢視過去某個revision(版本)的key-value的存儲。同時為了實作細粒度的存儲管理,叢集管理者可以自定義配置鍵空間曆史儲存政策。etcd v3會借助自定義的計時器廢棄舊鍵的版本(revision)典型的etcd v3叢集可以使被替代的key的資料保留數小時。是以,etcd v3具備對用戶端長時間斷開連接配接的可靠處理能力,突破了僅能處理暫态網絡中斷的限制。在這種情況下,watch用戶端可以直接根據最近以此觀察到的revision進行恢複。類似的,如果用戶端希望讀取某個時間點的key-value存儲狀态,則隻需要在請求中附帶某個revision的值即可傳回該revision送出時間點的key空間狀态

鍵區間

etcd v3資料模型采用扁平key空間,為所有key建立索引。該模型有别于其他常見的采用層級系統将key組建為目錄(directory)的key-value存儲系統。key不再以目錄的形式列出,而是左閉右開的形式,如[ key1,keyN)。對于key去就按的操作,既保留了對目錄形式key的查找能力。

事務

在 etcd v3中,事務就是一個原子的,針對key-value存儲操作的If/Then/Else結構。事務提供了一個原語,用于将請求歸并到一起放在原子塊中,這些原子塊的執行條件以key-value存儲裡的内容為依據。事務可以用來保護key不受其他并發更新操作的修改,也可以建構CAS操作,并以此作為更高層次并發控制的基礎。

所有的事務都由一個比較“連接配接(conjunction)”來守護,類似于if聲明,每個比較都會檢查背景存儲中的一個key。這個檢查可以是如下内容:該key在背景存儲是否有value?該key的value是否等于某個給定的值?除了value,還可以檢查這個key的revision或者version。。如果所有的比較都傳回true,那麼就說明該事務成功執行了,并且執行該事務success請求塊中的操作,反之就說明該事務失敗了,轉而執行該事務failure請求塊中的操作

Event

對于每個key而言,發生的每一個變化都以Event消息進行表示。一個Event消息提供了變化的類型與對應改變的資料,其字段定義代碼如下:

message Event{
	enum EventType{
			PUT = 0;
			DELETE = 1;
		}
		EventType type  =1;
		KeyValue kv = 2; //與Event管來奶的key-value
		KeyValue prev_kv = 3; //對應緊接着Event之前的revision的key-value
}
           
  • type

    :Event類型,分為PUT類型和DELETE類型。PUT類型表明新的資料已經存儲到對應的key,DELETE類型表明key已經被删除了

  • KV:與Event關聯的key-value。一個PUT Event包含目前的KV,一個Version=1的PUT Event表明這個key是建立的。一個DELETE Event包含被删除的key和該key被删除時的modification revision
  • Prev——KV:該key在發生此Event之前最近一刻revision的key-value對。為了節省帶寬,隻有在Watch請求中顯示地啟動該選項時才會在響應中傳回該值

流式Watch

wacth操作是長期持續存在地請求,watch流是雙向的。Client通過寫入流來建立watch,另一方面,Client通過讀入流來接收watch到的Event。

etcd v3的watch機制確定檢測到的Event具有有序,可靠與原子化的特點,各個特點對應的意義如下:

  • 有序:Event按照revision排序,後發生的Event不會在前面的Event之前出現在watch流中
  • 可靠:某個事件序列不會一樓1其中任意的子序列,假設有三個Event,按發生事件依次排序a<b<b,如果watch接收到Event a和c,那麼能保證b也被接收了
  • 原子性:Event清單確定完整的revision,在相同得revision多個key上,更新不會分裂為幾個事件清單

Lease API

租約是一種檢測用戶端活躍度的機制。Lease機制應用廣泛。租約是有生存時間的,叢集為租約授予一個TTL。當key被授予一個租約時,他的生存時間即為Lease生存時間。當Lease的TTL到期時,所有與之關聯的key都會被删除。

如果etcd叢集在給定的TT周期内沒有收到一個keepAlive消息維持租約,那麼該租約将過期。etcd3所支援的租約機制可為etcd中的某一個或者多個key關聯租約,一個key最多關聯一個租約。當一個租約過期時,所有關聯的key都會被自動删除。每個過期的key都會産生一個“删除”事件