etcd 是基於 raft算法的分布式鍵值數據庫,生來就為集群化而設計的。
比較好的操作:
alias etcdctl='etcdctl --endpoints=https://10.20.16.227:2379,https://10.20.16.228:2379,https://10.20.16.229:2379 --cacert=/data/cloud/ssl/ca.pem --cert=/data/cloud/ssl/etcd.pem --key=/data/cloud/ssl/etcd-key.pem'
一、總體結構
Raft層:協議保證數據的一致性和高可用;
API層:(在etcd3里面變成了grpc server),主要處理client的操作請求以及節點間的數據同步和心跳保持
邏輯層:負責etcd中事務操作的邏輯,是api server的命令的具體實現
存儲層:負責具體的數據持久存儲操作。它分為兩部分,entry 負責實際的日志數據存儲。snapshot 則是對日志數據的狀態存儲以防止過多的數據存在。
二、etcd接口
etcd 提供的接口,分為了 5 組:
第一組是Put與Delete。put與delete的操作都非常簡單,只需要提供一個 key 和一個 value,就可以向集群中寫入數據了,刪除數據的時候只需要指定 key 即可;
第二組是查詢操作。etcd 支持兩種類型的查詢:第一種是指定單個 key 的查詢,第二種是指定的一個 key 的范圍;
第三組是數據訂閱。etcd 提供了Watch機制,我們可以利用watch實時訂閱到etcd中增量的數據更新,watch支持指定單個key,也可以指定一個key的前綴,在實際應用場景中的通常會采用第二種形勢;
第四組事務操作。etcd 提供了一個簡單的事務支持,用戶可以通過指定一組條件滿足時執行某些動作,當條件不成立的時候執行另一組操作,類似於代碼中的if else語句,etcd 確保整個操作的原子性;
第五組是Leases接口。Leases接口是分布式系統中常用的一種設計模式,其用法后面會具體展開。
二、etcd選主過程
raft算法需要半數以上投票才能有 leader。偶數節點雖然多了一台機器,但是容錯能力是一樣的,也就是說,設置偶數節點,沒增加什么能力,還浪費了一台機器。同時etcd 是通過復制數據給所有節點來達到一致性,因此偶數的多一台機器增加不了性能,反而會拉低寫入速度。
etcd 是高可用的,允許部分機器故障,以標准的3 節點etcd 集群,最大容忍1台機器宕機,下面以最簡單的leader宕機來演示raft 的投票邏輯,以實際的運行日志來驗證並理解。
場景:正常運行的三台etcd:100、101、102。當前任期為 7,leader 為 101機器。現在使101 宕機。宕機前:101為 leader,3個member。宕機后:102 成為新 leader,2 個 member
過程:
將 101 機器的 etcd 停止,此時只剩 2 台,但總數為 3
101停止etcd 的運行
102(91d63231b87fadda) 收到消息,發現101(8a4bb0af2f19bd46)心跳超時,於是發起了新一輪選舉,任期為 7+1=8
102(91d63231b87fadda)成為新一任的候選人,然后自己投給了自己,獲得 1 票
102(91d63231b87fadda)發送給 掛掉的101 和 另一個100,希望他們也投給自己
100 (9feab580a25dd270)收到了 102 的拉票消息,因為任期 8 大於當前100機器所處的 7,於是知道是發起了新的一輪選舉,因此回應 101,我給你投票。這里任期term是關鍵,也就是說,100 和 102 誰先感受到 101 宕機,發起投票,誰就是新的 leader,這個也和進程初始的啟動時間有關。102 肯定收不到 101 的回應,因為 101 已經掛掉
91d63231b87fadda elected leader 91d63231b87fadda at term 8102 獲得了 2 票,一票是自己,一票是 100,超過半數,成為新的 leader。任期為 8
三、etcd 是強一致性
etcd是強一致性,讀和寫都可以保證線性一致
線性一致性讀需要在所有節點走一遍確認,查詢速度會有所降低,要開啟線性一致性讀,在不同的 client是有所區別的:v2 版本:通過 sdk訪問時,quorum=true 的時候讀取是線性一致的,通過etcdctl訪問時,該參數默認為true。v3 版本:通過 sdk訪問時,WithSerializable=true 的時候讀取是線性一致的,通過etcdctl訪問時consistency=“l”表示線性(默認為 l,非線性為 s)
為了保證線性一致性讀,早期的 etcd(_etcd v3.0 _)對所有的讀寫請求都會走一遍 Raft 協議來滿足強一致性。然而通常在現實使用中,讀請求占了 etcd 所有請求中的絕大部分,如果每次讀請求都要走一遍 raft 協議落盤,etcd 性能將非常差。
因此在 etcd v3.1 版本中優化了讀請求(PR#6275),使用的方法滿足一個簡單的策略:每次讀操作時記錄此時集群的 commit index,當狀態機的 apply index 大於或者等於 commit index 時即可返回數據。由於此時狀態機已經把讀請求所要讀的 commit index 對應的日志進行了 apply 操作,符合線性一致讀的要求,便可返回此時讀到的結果。
四、etcd 常見問題
4.1 修復etcd數據
一個節點宕機,並不會影響整個集群的正常工作,可以修復。
(1) 移出該節點:etcdctl member remove xx(可以通過member list獲取XX)
(2) 停止etcd服務
(3) 需要將配置中的 cluster_state改為:existing,因為是加入已有集群,不能用 new
修復機器問題,刪除舊的數據目錄,重新啟動 etcd 服務
(4) 加入 memeber: etcdctl member add xxx –peer-urls=https://x.x.x.x:2380
(5) 驗證:etcdctl endpoint status
4.2 遷移數據
使用 etcdctl snapshot save 來保存現有數據,新集群更換后,使用 restore 命令恢復數據,在執行快照時會產生一個 hash 值,來標記快照內容后面恢復時用於校驗,如果你是直接復制的數據文件,可以–skip-hash-check 跳過這個檢查。
etcdctl save etcd-data-20171002-2.snapshot
etcdctl snapshot restore ./etcd-data-20171002-2.snapshot --data-dir=/var/lib/etcd/etcd.node1.etcd(這里的路徑一定要對)
4.3通過證書訪問etcd
etcdctl --endpoints https://node1:2379,https://node2:2379,https://node3:2379 endpoint status --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/etcd-server.pem --key=/etc/kubernetes/ssl/etcd-server.key
4.4 etcd獲取數據
export ETCDCTL_API=3
etcdctl get / --keys-only --prefix
etcdctl get ** --prefix