好文推薦 | etcd 問題、調優、監控

點擊上方“朱小廝的博客”,選擇“設爲星標”

後臺回覆"加羣",加入新技術

來源:www.xuyasong.com/?p=1983

etcd 原理解析:讀《etcd 技術內幕》這篇文章主要是原理性的內容,本文主要是實踐角度,談談平時用到的一些操作和監控。

高可用

etcd 是基於 raft算法的分佈式鍵值數據庫,生來就爲集羣化而設計的,由於Raft算法在做決策時需要超半數節點的投票,所以etcd集羣一般推薦奇數節點,如3、5或者7個節點構成一個集羣。

以上是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

91d63231b87fadda [term 7] received MsgTimeoutNow from 8a4bb0af2f19bd46 and starts an election to get leadership.
  • 102(91d63231b87fadda)成爲新一任的候選人,然後自己投給了自己,獲得 1 票

91d63231b87fadda became candidate at term 8
91d63231b87fadda received MsgVoteResp from 91d63231b87fadda at term 8
  • 102(91d63231b87fadda)發送給 掛掉的101 和 另一個100,希望他們也投給自己

91d63231b87fadda [logterm: 7, index: 4340153] sent MsgVote request to 8a4bb0af2f19bd46 at term 8


91d63231b87fadda [logterm: 7, index: 4340153] sent MsgVote request to 9feab580a25dd270 at term 8
  • 102 肯定收不到 101 的迴應,因爲 101 已經掛掉

etcd[24203]: lost the TCP streaming connection with peer 8a4bb0af2f19bd46 (stream MsgApp v2 reader)
  • 100 (9feab580a25dd270)收到了 102 的拉票消息,因爲任期 8 大於當前100機器所處的 7,於是知道是發起了新的一輪選舉,因此迴應 101,我給你投票。這裏任期term是關鍵,也就是說,100 和 102 誰先感受到 101 宕機,發起投票,誰就是新的 leader,這個也和進程初始的啓動時間有關。

9feab580a25dd270 [term: 7] received a MsgVote message with higher term from 91d63231b87fadda [term: 8]
9feab580a25dd270 became follower at term 8
9feab580a25dd270 [logterm: 7, index: 4340153, vote: 0] cast MsgVote for 91d63231b8
9feab580a25dd270 elected leader 91d63231b87fadda at term 8
  • 102 獲得了 2 票,一票是自己,一票是 100,超過半數,成爲新的 leader。任期爲 8

91d63231b87fadda elected leader 91d63231b87fadda at term 8
  • 更換完成

必須是奇數節點嗎

etcd官方推薦3、5、7個節點,雖然raft算法也是半數以上投票纔能有 leader,但奇數只是推薦,其實偶數也是可以的。如 2、4、8個節點。分情況說明:

  • 1 個節點:就是單實例,沒有集羣概念,不做討論

  • 2 個節點:是集羣,但沒人會這麼配,這裏說點廢話:雙節點的etcd能啓動,啓動時也能有主,可以正常提供服務,但是一臺掛掉之後,就選不出主了,因爲他只能拿到1票,剩下的那臺也無法提供服務,也就是雙節點無容錯能力,不要使用。

2節點正常運行:

1臺宕機後:

  • 3 節點:標準的3 節點etcd 集羣只能容忍1臺機器宕機,掛掉 1 臺的邏輯上邊已經演示過,如果再掛 1 臺,就和 2節點的情形一致了,一直選,一直增加任期,但就是選不出來,服務也就不可用了

  • 4 節點:最大容忍1 臺

  • 5 節點:最大容忍 2 臺

  • 6 節點:最大容忍 2 臺

你會發現偶數節點雖然多了一臺機器,但是容錯能力是一樣的,也就是說,你可以設置偶數節點,但沒增加什麼能力,還浪費了一臺機器。同時etcd 是通過複製數據給所有節點來達到一致性,因此偶數的多一臺機器增加不了性能,反而會拉低寫入速度。

機器越多越好嗎

etcd 集羣是一個 Raft Group,沒有 shared。所以它的極限有兩部分,一是單機的容量限制,內存和磁盤;二是網絡開銷,每次 Raft 操作需要所有節點參與,每一次寫操作需要集羣中大多數節點將日誌落盤成功後,Leader 節點才能修改內部狀態機,並將結果返回給客戶端。因此節點越多性能越低,所以擴展很多 etcd 節點是沒有意義的,一般是 3、5、7, 7 個也足夠了。

在 k8s 中一般是3*master機器做高可用,也就是 3節點的 etcd。也有人將 etcd獨立於 k8s集羣之外,來更好地擴展 etcd 集羣,或者根據 k8s 的資源來拆分 etcd,如 events 放在單獨的 etcd 集羣中。不同的副本數視業務規模而定,3,5,7 都可以。

腦裂問題

集羣化的軟件總會提到腦裂問題,如ElasticSearch、Zookeeper集羣,腦裂就是同一個集羣中的不同節點,對於集羣的狀態有了不一樣的理解。

etcd 中有沒有腦裂問題?答案是:沒有

The majority side becomes the available cluster and the minority side is unavailable; there is no “split-brain” in etcd.

以網絡分區導致腦裂爲例,一開始有5個節點, Node 5 爲 Leader

由於出現網絡故障,124 成爲一個分區,35 成爲一個分區, Node 5 的 leader 任期還沒結束的一段時間內,仍然認爲自己是當前leader,但是此時另外一邊的分區,因爲124無法連接 5,於是選出了新的leader 1,網絡分區形成。

35分區是否可用?如果寫入了1而讀取了 5,是否會讀取舊數據(stale read)?

答:35分區屬於少數派,被認爲是異常節點,無法執行寫操作。寫入 1 的可以成功,並在網絡分區恢復後,35 因爲任期舊,會自動成爲 follower,異常期間的新數據也會從 1 同步給 35。

而 5 的讀請求也會失敗,etcd 通過ReadIndex、Lease read保證線性一致讀,即節點5在處理讀請求時,首先需要與集羣多數節點確認自己依然是Leader並查詢 commit index,5做不到多數節點確認,因此讀失敗。

因此 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 的完整安裝過程。下載 etcd3.4 的 release 包

生成證書

1.ca-config.json

創建用來生成 CA 文件的 JSON 配置文件,這個文件後面會被各種組件使用,包括了證書過期時間的配置,expiry字段

{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "demo": {
        "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ],
        "expiry": "87600h"
      }
    }
  }}

2.ca-csr.json

創建用來生成 CA 證書籤名請求(CSR)的 JSON 配置文件

{
  "CN": "demo",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "demo",
      "OU": "cloudnative"
    }
  ]}

3.生成基礎 ca 證書

cfssl gencert -initca ca-csr.json | cfssljson -bare ca

執行後會生成三個文件:

  • ca.csr:證書籤名請求,一般用於提供給證書頒發機構,自籤就不需要了

  • ca.pem:證書,公共證書

  • ca-key.pem:CA密鑰

  1. 生成 etcd 證書

增加etcd-csr.json文件,ip 需要填寫三臺 etcd 機器的 ip

{
    "CN": "demo",
    "hosts": [
        "127.0.0.1",
        "ip1","ip2","ip3"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "ST": "BeiJing",
            "L": "BeiJing",
            "O": "demo",
            "OU": "cloudnative"
        }
    ]}

這裏的hosts字段中指定了授權使用該證書的IP和域名列表,因爲現在要生成的證書需要被etcd集羣各個節點使用,所以這裏指定了各個節點的IP

生成證書:

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=jpaas etcd-csr.json | cfssljson -bare etcd

創建etcd 的 CA 證書:這裏需要4 個文件

  • etcd-csr.json:etcd的證書配置

  • ca.pem:基礎公鑰

  • ca-key.pem:基礎私鑰

  • ca-config.json:配置文件,如過期時間

執行後會生成三個文件:

  • etcd.csr

  • etcd.pem

  • etcd-key.pem

在一臺機器上做證書生成,生成後將這三個文件拷貝到其他幾臺機器。

部署集羣

etcd 啓動配置示例

./etcd \
--name=etcd-0 \
--client-cert-auth=true \
--cert-file=/etc/etcd/ssl/etcd.pem \
--key-file=/etc/etcd/ssl/etcd-key.pem \
--peer-cert-file=/etc/etcd/ssl/etcd.pem \
--peer-key-file=/etc/etcd/ssl/etcd-key.pem \
--trusted-ca-file=/etc/etcd/ssl/ca.pem \
--peer-trusted-ca-file=/etc/etcd/ssl/ca.pem \
--initial-advertise-peer-urls https://100.0.0.0:2380 \--listen-peer-urls https://100.0.0.0:2380 \--listen-client-urls https://100.0.0.0:2379,https://127.0.0.1:2379 \--advertise-client-urls https://100.0.0.0:2379 \--initial-cluster-token etcd-cluster \
--initial-cluster etcd-0=https://100.0.0.0:2380,etcd-1=https://100.0.0.1:2380,etcd-2=https://100.0.0.2:2380 \--initial-cluster-state new \
--quota-backend-bytes=8589934592 \
--auto-compaction-retention=10 \
--enable-pprof=true \
--data-dir=/var/lib/etcd

etcdctl 命令

因爲我們的 etcd 配置了證書,所有的命令都要帶上證書訪問,如:

ETCDCTL_API=3 ./etcdctl --endpoints=https://0:2379,https://1:2379,https://2:2379 --cacert /etc/etcd/ssl/ca.pem --cert /etc/etcd/ssl/etcd.pem --key /etc/etcd/ssl/etcd-key.pem endpoint status --write-out=table

etcd 版本爲 3.4,可以ETCDCTL_API=3,或ETCDCTL_API=2,默認情況下用的就是v3了,可以不用聲明ETCDCTL_API

證書太長就不寫了,以下命令均爲無證書版:

  • version: 查看版本

  • member list: 查看節點狀態,learner 情況

  • endpoint status: 節點狀態,leader 情況

  • endpoint health: 健康狀態與耗時

  • alarm list: 查看警告,如存儲滿時會切換爲只讀,產生 alarm

  • alarm disarm:清除所有警告

  • set app demo: 寫入

  • get app: 獲取

  • update app demo1:更新

  • rm app: 刪除

  • mkdir demo 創建文件夾

  • rmdir dir 刪除文件夾

  • backup 備份

  • compaction:壓縮

  • defrag:整理碎片

  • watch key 監測 key 變化

  • get / –prefix –keys-only: 查看所有 key

  • –write-out= tables,可以用表格形式輸出更清晰,注意有些輸出並不支持tables

注意,member list並沒有展示 leader 信息,展示的是 learner,learner的含義後面會解釋

參數配置

版本建議使用 3.4 及以上,3.4存儲容量做了提升,降低了讀寫延遲。

etcd 的配置參數有很多,如果你覺得自己的etcd遇到了瓶頸,先不要急着提 issue 改代碼,先看下這些參數的含義,也許調一下配置就能解決。

etcd 的配置遇到按照功能來劃分:

代理功能

  • etcd gateway

  • etcd grpc-proxy

每個訪問 etcd 的應用都要有 etcd 集羣的 endpoints。如果在同一臺服務器上的多個應用訪問同一個 etcd 集羣,大家都得配置一樣的endpoints。如果這個時候 etcd 集羣更換了集羣或者 ip,每個應用都需要更新它的終端列表,這種重新配置是繁瑣且容易出錯的。

這裏提一下,etcd 的 client 使用的是 grpc 訪問,client會根據傳入的 endpoints 做客戶端負載均衡。

etcd gateway就是一個典型的轉發代理,屏蔽掉後面的endpoints 信息。不過需要注意的是,etcd gateway在 TCP 層,不支持 https 類型的 endpoints。

成員配置

  • –data-dir: 數據目錄

  • –snapshot-count: 最大快照次數,默認10萬

  • –heartbeat-interval: 心跳週期默認 100ms

  • –election-timeout: 選舉超時1s

  • –max-snapshots: 最大保留快照數,默認 5 個

  • –quota-backend-bytes: DB 數據大小,比如 10G,50G。

  • –auto-compaction-retention: 自動壓縮,默認爲 0 不開啓,k8s中 apiserver會開啓這個壓縮,5 分鐘一次。如果你的 etcd 還被其他人使用,這裏也可以設置下時間

  • –enable-pprof: 開啓pprof分析

  • –metrics: 默認爲basic模式,extensive代表暴露histogram類型 metric

  • –log-level: 日誌等級。info, warn, error, panic, or fatal

證書配置

--client-cert-auth=true \
--cert-file=/etc/etcd/ssl/etcd.pem \
--key-file=/etc/etcd/ssl/etcd-key.pem \
--peer-cert-file=/etc/etcd/ssl/etcd.pem \
--peer-key-file=/etc/etcd/ssl/etcd-key.pem \
--trusted-ca-file=/etc/etcd/ssl/ca.pem \
--peer-trusted-ca-file=/etc/etcd/ssl/ca.pem \

集羣配置

--peer-trusted-ca-file=/etc/etcd/ssl/ca.pem \
--initial-advertise-peer-urls https://100.0.0.0:2380 \--listen-peer-urls https://100.0.0.0:2380 \--listen-client-urls https://100.0.0.0:2379,https://127.0.0.1:2379 \--advertise-client-urls https://100.0.0.0:2379 \--initial-cluster-token etcd-cluster \
--initial-cluster etcd-0=https://100.0.0.0:2380,etcd-1=https://100.0.0.1:2380,etcd-2=https://100.0.0.2:2380 \--initial-cluster-state new \

配置調優

一般情況下,etcd 默認模式不會有什麼問題,影響 etcd 的因素一般是網絡和存儲延時,尤其是跨地域、跨機房的集羣。

網絡延遲

因爲 leader 和 member 之間有頻繁的心跳和數據複製,因此網絡擁塞影響會很大,當然長時間失敗會無響應會導致 etcd 集羣不可用。一般是將 etcd 集羣規劃在一個地域或一個機房內,並且使用tc提高帶寬和優先級。

心跳間隔

etcd 的一致性協議依賴兩個時間參數。

  • –heartbeat-interval:心跳間隔,即 leader 通知member 並保證自己 leader 地位的心跳,默認是 100ms,這個應該設置爲節點間的 RTT 時間。

  • –election-timeout:選舉超時時間,即 member 多久沒有收到 leader 的迴應,就開始自己競選 leader,默認超時時間爲 1s

默認值有可能不滿足你的需求,如你的網絡延遲較高,RTT 大於 100,就應該按真實延遲來,比如這個 issue,官方文檔也對心跳的設置給了詳細的解釋和配置建議:https://github.com/etcd-io/etcd/blob/master/Documentation/tuning.md

如果心跳間隔太短,則 etcd 將發送不必要的消息,從而增加 CPU 和網絡資源的使用。另一方面,心跳間隔過長會導致選舉超時。較高的選舉超時時間需要更長的時間來檢測領導者失敗。測量往返時間(RTT)的最簡單方法是使用PING。

磁盤 IO

除了網絡延遲,磁盤 IO 也嚴重影響 etcd 的穩定性, etcd需要持久化數據,對磁盤速度很敏感,強烈建議對 ETCD 的數據掛 SSD。

另外,要確認機器上沒有其他高 IO 操作,否則會影響 etcd 的 fsync,導致 etcd 丟失心跳,leader更換等。一般磁盤有問題時,報錯的關鍵字類似於:

took too long (1.483848046s) to execute
 etcdserver: failed to send out heartbeat on time 

磁盤 IO 可以通過監控手段提前發現,並預防這類問題的出現

快照

etcd的存儲分爲內存存儲和持久化(硬盤)存儲兩部分,內存中的存儲除了順序化的記錄下所有用戶對節點數據變更的記錄外,還會對用戶數據進行索引、建堆等方便查詢的操作。而持久化則使用預寫式日誌(WAL:Write Ahead Log)進行記錄存儲。

在WAL的體系中,所有的數據在提交之前都會進行日誌記錄。在etcd的持久化存儲目錄中,有兩個子目錄。一個是WAL,存儲着所有事務的變化記錄;另一個則是snapshot,用於存儲某一個時刻etcd所有目錄的數據。通過WAL和snapshot相結合的方式,etcd可以有效的進行數據存儲和節點故障恢復等操作。

既然有了WAL實時存儲了所有的變更,爲什麼還需要snapshot呢?隨着使用量的增加,WAL存儲的數據會暴增,爲了防止磁盤很快就爆滿,etcd默認每10000條記錄做一次snapshot,經過snapshot以後的WAL文件就可以刪除。而通過API可以查詢的歷史etcd操作默認爲1000條。

客戶端優化

etcd 的客戶端應該避免一些頻繁操作或者大對象操作,如:

  • put 時避免大 value,精簡再精簡(例如 k8s 中 crd 使用)

  • 避免創建頻繁變化的 kv(例如 k8s 中 node 信息彙報),如 node-lease

  • 避免創建大量 lease,儘量選擇複用(例如 k8s 中 event 數據管理)

  • 合理利用 apiserver 中的緩存,避免大量請求打到 etcd上,如集羣異常恢復後大量 pod同步

其他

你可能還看到過lease revoke 、boltdb、內存優化等方式,這些已經合入了最新的 etcd3.4版本,因此選擇最新的 release 版本也是提高穩定性的一種方式。

壓縮機制

Etcd作爲 KV 存儲,會爲每個 key 都保留歷史版本,比如用於發佈回滾、配置歷史等。

對 demo 寫入值爲 101,然後更爲爲 102,103。-w json 可以輸出這次寫入的 revision

etcdctl put demo 101 -w json
etcdctl put demo 102 -w json
etcdctl put demo 103 -w json


返回類似:{"header":{"cluster_id":4871617780647557296,"member_id":3135801277950388570,"revision":434841,"raft_term":2}}

取值:

etcdctl get demo 默認 --rev=0即最新值=103如果要拿到歷史值,需要制定 rev 版本
etcdctl get demo  --rev=434841,得到 102

觀察 key的變化:

etcdctl watch  foo --rev=0

歷史版本越多,存儲空間越大,性能越差,直到etcd到達空間配額限制的時候,etcd的寫入將會被禁止變爲只讀,影響線上服務,因此這些歷史版本需要進行壓縮。

數據壓縮並不是清理現有數據,只是對給定版本之前的歷史版本進行清理,清理後數據的歷史版本將不能訪問,但不會影響現有最新數據的訪問。

手動壓縮

etcdctl compact 5。 在 5 之前的所有版本都會被壓縮,不可訪問如果 etcdctl get --rev=4 demo,會報錯Error:  rpc error: code = 11 desc = etcdserver: mvcc: required revision has been compacted

手動操作畢竟繁瑣,Etcd提供了啓動參數 “–auto-compaction-retention” 支持自動壓縮 key 的歷史版本,以小時爲單位

etcd --auto-compaction-retention=1 代表 1 小時壓縮一次

v3.3之上的版本有這樣一個規則:

如果配置的值小於1小時,那麼就嚴格按照這個時間來執行壓縮;如果配置的值大於1小時,會每小時執行壓縮,但是採樣還是按照保留的版本窗口依然按照用戶指定的時間週期來定。

k8s api-server支持定期執行壓縮操作,其參數裏面有這樣的配置:

– etcd-compaction-interval 即默認 5 分鐘一次

你可以在 etcd 中看到這樣的壓縮日誌,5 分鐘一次:

Apr 25 11:05:20  etcd[2195]: store.index: compact 433912Apr 25 11:05:20  etcd[2195]: finished scheduled compaction at 433912 (took 1.068846ms)Apr 25 11:10:20  etcd[2195]: store.index: compact 434487Apr 25 11:10:20  etcd[2195]: finished scheduled compaction at 434487 (took 1.019571ms)Apr 25 11:15:20  etcd[2195]: store.index: compact 435063Apr 25 11:15:20  etcd[2195]: finished scheduled compaction at 435063 (took 1.659541ms)Apr 25 11:20:20  etcd[2195]: store.index: compact 435637Apr 25 11:20:20  etcd[2195]: finished scheduled compaction at 435637 (took 1.676035ms)Apr 25 11:25:20  etcd[2195]: store.index: compact 436211Apr 25 11:25:20  etcd[2195]: finished scheduled compaction at 436211 (took 1.17725ms)

碎片整理

進行壓縮操作之後,舊的revision被清理,會產生內部的碎片,內部碎片是指空閒狀態的,能被etcd使用但是仍然消耗存儲空間的磁盤空間,去碎片化實際上是將存儲空間還給文件系統。

# defrag命令默認只對本機有效
etcdctl defrag


# 如果帶參數--endpoints,可以指定集羣中的其他節點也做整理
etcdctl defrag --endpoints

如果etcd沒有運行,可以直接整理目錄中db的碎片

etcdctl defrag --data-dir <path-to-etcd-data-dir>

碎片整理會阻塞對etcd的讀寫操作,因此偶爾一次大量數據的defrag最好逐臺進行,以免影響集羣穩定性。

etcdctl執行後的返回 Finished defragmenting etcd member[https://127.0.0.1:2379]

存儲空間

Etcd 的存儲配額可保證集羣操作的可靠性。如果沒有存儲配額,那麼 Etcd 的性能就會因爲存儲空間的持續增長而嚴重下降,甚至有耗完集羣磁盤空間導致不可預測集羣行爲的風險。一旦其中一個節點的後臺數據庫的存儲空間超出了存儲配額,Etcd 就會觸發集羣範圍的告警,並將集羣置於接受讀 key 和刪除 key 的維護模式。只有在釋放足夠的空間和消除後端數據庫的碎片之後,清除存儲配額告警,集羣才能恢復正常操作。

啓動 etcd 時。–quota-backend-bytes 默認爲 2G,2G 一般情況下是不夠用的,

你可以通過 etcdctl endpoint status 命令來查看當前的存儲使用量

在 3.4 版本中,etcd 的存儲容量得到了提高,你可以設置 100G 的存儲空間,當然並不是越大越好,key 存儲過多性能也會變差,根據集羣規模適當調整。

另外,–max-request-bytes 限制了請求的大小,默認值是1572864,即1.5M。在某些場景可能會出現請求過大導致無法寫入的情況,可以調大到10485760即10M。

如果遇到空間不足,可以這樣操作:

# 獲取當前版本號
$ rev=$(ETCDCTL_API=3 etcdctl  endpoint status --write-out="json" | egrep -o '"revision":[0-9]*' | egrep -o '[0-9]*')# 壓縮所有舊版本
$ ETCDCTL_API=3 etcdctl compact $rev# 去碎片化
$ ETCDCTL_API=3 etcdctl defrag
# 取消警報
$ ETCDCTL_API=3 etcdctl alarm disarm
# 測試通過
$ ETCDCTL_API=3 etcdctl put key0 1234

快照備份

etcd可以定期做備份、以保證數據更好的持久化。通過加載備份數據,etcd可以將集羣恢復到具有已知良好狀態的時間點。

使用命令etcdctl:

etcdctl snapshot save backup.db


etcdctl --write-out=table snapshot status backup.db


+----------+----------+------------+------------+|   HASH   | REVISION | TOTAL KEYS | TOTAL SIZE |+----------+----------+------------+------------+| fe01cf57 |       10 |          7 | 2.1 MB     |+----------+----------+------------+------------+

learner 角色

learner 是 etcd 3.4 版本中增加的新角色,類似於 zookeeper 的 observer, 不參與 raft 投票選舉。通過這個新角色的引入,降低了加入新節點時給老集羣的額外壓力,增強了集羣的穩定性。除此之外還可以使用它作爲集羣的熱備或服務一些讀請求。

舉例,如果 etcd集羣需要加入一個新節點,新加入的 etcd 成員因爲沒有任何數據,因此需要從 leader 那裏同步數據,直到趕上領導者的日誌爲止。這樣就會導致 leader 的網絡過載,導致 leader 和 member 之間的心跳可能阻塞。然後就開始了新的leader選舉,也就是說,具有新成員的集羣更容易受到領導人選舉的影響。領導者的選舉以及隨後向新成員的更新都容易導致一段時間的羣集不可用,這種是不符合預期,風險也是很大的。

因此爲了解決這個問題,raft 4.2.1 論文中介紹了一種新的節點角色:Learner。加入集羣的節點不參與投票選舉,只接收 leader 的 replication message,直到與 leader 保持同步爲止。

learner 在網絡分區等場景下的處理,可以詳細參考:https://etcd.io/docs/v3.3.12/learning/learner/

具體操作:

# 增加一個節點作爲learner
member add --learner


# 當learner的日誌趕上了leader的進度時,將learner提升爲有投票權的成員,然後該成員將計入法定人數
member promote


etcd server 會驗證 promote 請求以確保真實

在提升之前,learner僅充當備用節點,leader無法轉移給learner。learner拒絕客戶端讀寫(客戶端平衡器不應將請求路由到learner)

另外,etcd限制了集羣可以擁有的learner總數,並避免了日誌複製導致領導者過載。learner永遠不會自我提升。

etcd client v3

Etcd client v3是基於grpc實現的,而grpc又是基於http2.0實現的,借用了很多 http2的優勢如二進制通訊、多路複用等,因此整體上借用grpc的框架做地址管理、連接管理、負載均衡等,而底層對每個Etcd的server只需維持一個http2.0連接。

Etcd client v3實現了grpc中的Resolver接口,用於Etcd server地址管理。當client初始化或者server集羣地址發生變更(可以配置定時刷新地址)時,Resolver解析出新的連接地址,通知grpc ClientConn來響應變更。

client v3的原理解析可以看這篇文章:https://www.jianshu.com/p/281b80ae619b

我們是用etcd client做應用的選主操作,可以看下這篇

這裏提一下,最早的時候以爲 kubernetes 中的 scheduler、controller-manager是基於 etcd 做選主的,client拿來直接用很方便。後來發現不是,kubernetes 是用搶佔 endpoint 資源的方式實現選主邏輯,不依賴外部 etcd,這麼想來也合理,嚴格來講,etcd 不是kubernetes的東西,不應該有太多依賴。

k8s 中 scheduler 的選主邏輯可以看這篇文章

問題排查

列幾個常遇到的 etcd 問題,後面監控部分會提到如何監測、預防這類問題

一個節點宕機

一個節點宕機,並不會影響整個集羣的正常工作,慢慢修復。

  1. 移出該節點:etcdctl member remove xx

  2. 修復機器問題,刪除舊的數據目錄,重新啓動 etcd 服務

  3. 因爲 etcd 的證書需要簽入所有節點 ip,因此這裏的節點不能更改 ip,否則要全部重簽證書,重啓服務

  4. 重啓啓動 etcd 時,需要將配置中的 cluster_state改爲:existing,因爲是加入已有集羣,不能用 new

  5. 加入 memeber:etcdctl member add xxx –peer-urls=https://x.x.x.x:2380

  6. 驗證:etcdctl endpoint status

遷移數據

如果你的集羣需要更換所有的機器,包括更換 IP,那就得通過快照恢復的方式了

使用 etcdctl snapshot save 來保存現有數據,新集羣更換後,使用 restore 命令恢復數據,在執行快照時會產生一個 hash 值,來標記快照內容後面恢復時用於校驗,如果你是直接複製的數據文件,可以–skip-hash-check 跳過這個檢查。

遷移集羣會更換證書和端點,因此一定會影響上層服務,在遷移之前一定要做好新舊切換,如 apiserver 分批升級(會有部分數據不一致)、避免服務宕機時間過長等

failed to send out heartbeat on time

這個前面已經提過,大概率是因爲磁盤性能不足,導致心跳失敗,更換 SSD 或者排查機器上高 IO 的進程

詳細可以查看這個:https://github.com/etcd-io/etcd/blob/master/Documentation/faq.md#what-does-the-etcd-warning-failed-to-send-out-heartbeat-on-time-mean

request ... took too long to execute 這類報錯也是同理

mvcc: database space exceeded

存儲空間不足,參考上面提到的清理和恢復步驟,或者提高存儲空間

endpoints問題

儘量不要使用lb 作爲 etcd endpoints 配置,etcd client 是 grpc 訪問,請使用默認的 全量list ,客戶端做負載均衡的方式。詳細內容可以參考 grpc 負載均衡場景解析

監控

etcd 默認以/metrics的 path 暴露了監控數據,數據爲 prometheus 標準格式。

通過 metric 數據可以配置出如下面板,一般我們關心的數據,或者說需要配置報警的內容:

  • 是否有 leader:集羣就不可用了

  • leader 更換次數:一定時間內頻率過高一般是有問題,且leader 更換會影響到上層服務

  • rpc 請求速率:即 qps,可以評估當前負載

  • db 總大小:用於評估數據量、壓縮策略等

  • 磁盤讀寫延遲:這個很關鍵,延遲過高會導致集羣出現問題




後記

etcd 可以很簡單,畢竟只是 KV 存儲,也可以很複雜,代表了雲原生時代分佈式存儲的基石,本文中的內容只是工作中的問題描述,淺嘗輒止,不足之處,歡迎指正。

參考

  • https://ms2008.github.io/2019/12/04/etcd-rumor/

  • ReadIndex:https://zhuanlan.zhihu.com/p/31050303

  • LeaseRead:https://zhuanlan.zhihu.com/p/31118381

  • 線性一致讀:https://zhengyinyong.com/post/etcd-linearizable-read-implementation/

  • https://juejin.im/post/5d843b995188257e8e46e25d

  • https://skyao.io/learning-etcd3/documentation/op-guide/gateway.html

  • https://github.com/etcd-io/etcd/issues/7522

  • https://github.com/etcd-io/etcd/blob/master/Documentation/learning/design-learner.md

想知道更多?描下面的二維碼關注我

後臺回覆”加羣“獲取公衆號專屬羣聊入口

噹噹618圖書優惠活動,每滿100-50,我這裏還有一批“實付滿200再減30”的優惠碼TEGNC6 ,囤書薅羊毛再走一波~~(使用時間:5月18~6月1日,使用渠道:噹噹小程序或噹噹APP)

【原創系列 | 精彩推薦】

點個在看少個 bug ????

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章