etcd 性能測試與調優


etcd 是一個分布式一致性鍵值存儲。其主要功能有服務注冊與發現、消息發布與訂閱、負載均衡、分布式通知與協調、分布式鎖、分布式隊列、集群監控與 leader 選舉等。

1.etcd 性能優化

官方文檔原文:https://github.com/etcd-io/etcd/blob/master/Documentation/tuning.md 譯文參考:https://skyao.gitbooks.io/learning-etcd3/content/documentation/op-guide/performance.html

理解 etcd 的性能

決定 etcd 性能的關鍵因素,包括:

  • 延遲 (latency):延遲是完成操作的時間。
  • 吞吐量 (throughput):吞吐量是在某個時間期間之內完成操作的總數量。當 etcd 接收並發客戶端請求時,通常平均延遲隨着總體吞吐量增加而增加。

在通常的雲環境,比如 Google Compute Engine (GCE) 標准的 n-4 或者 AWS 上相當的機器類型,一個三成員 etcd 集群在輕負載下可以在低於 1 毫秒內完成一個請求,並在重負載下可以每秒完成超過 30000 個請求。

etcd 使用 Raft 一致性算法來在成員之間復制請求並達成一致。一致性性能,特別是提交延遲,受限於兩個物理約束:網絡 IO 延遲和磁盤 IO 延遲。完成一個 etcd 請求的最小時間是成員之間的網絡往返時延 (Round Trip Time / RTT),加需要提交數據到持久化存儲的 fdatasync 時間。在一個數據中心內的 RTT 可能有數百毫秒。在美國典型的 RTT 是大概 50ms, 而在大陸之間可以慢到 400ms。旋轉硬盤(注:指傳統機械硬盤) 的典型 fdatasync 延遲是大概 10ms。對於 SSD 硬盤, 延遲通常低於 1ms。為了提高吞吐量, etcd 將多個請求打包在一起並提交給 Raft。這個批量策略讓 etcd 在重負載試獲得高吞吐量。也有其他子系統影響到 etcd 的整體性能。每個序列化的 etcd 請求必須通過 etcd 的 boltdb 支持的(boltdb-backed) MVCC 存儲引擎, 它通常需要 10 微秒來完成。etcd 定期遞增快照它最近實施的請求,將他們和之前在磁盤上的快照合並。這個過程可能導致延遲尖峰(latency spike)。雖然在 SSD 上這通常不是問題,在 HDD 上它可能加倍可觀察到的延遲。而且,進行中的壓縮可以影響 etcd 的性能。幸運的是,壓縮通常無足輕重,因為壓縮是錯開的,因此它不和常規請求競爭資源。RPC 系統,gRPC,為 etcd 提供定義良好,可擴展的 API,但是它也引入了額外的延遲,尤其是本地讀取。

Etcd 的默認配置在本地網絡環境(localhost)下通常能夠運行的很好,因為延遲很低。然而,當跨數據中心部署 Etcd 或網絡延時很高時,etcd 的心跳間隔或選舉超時時間等參數需要根據實際情況進行調整。

網絡並不是導致延時的唯一來源。不論是 Follower 還是 Leader,其請求和響應都受磁盤 I/O 延時的影響。每個 timeout 都代表從請求發起到成功返回響應的總時間。

時間參數

Etcd 底層的分布式一致性協議依賴兩個時間參數來保證節點之間能夠在部分節點掉錢的情況下依然能夠正確處理主節點的選舉。第一個參數就是所謂的心跳間隔,即主節點通知從節點它還是領導者的頻率。實踐數據表明,該參數應該設置成節點之間 RTT 的時間。Etcd 的心跳間隔默認是 100 毫秒。第二個參數是選舉超時時間,即從節點等待多久沒收到主節點的心跳就嘗試去競選領導者。Etcd 的選舉超時時間默認是 1000 毫秒。

調整這些參數值是有條件的,此消波長。心跳間隔值推薦設置為臨近節點間 RTT 的最大值,通常是 0.5~1.5 倍 RTT 值。如果心跳間隔設得太短,那么 Etcd 就會發送沒必要的心跳信息,從而增加 CPU 和網絡資源的消耗;如果設得太長,就會導致選舉等待時間的超時。如果選舉等待時間設置的過長,就會導致節點異常檢測時間過長。評估 RTT 值的最簡單的方法是使用 ping 的操作。

選舉超時時間應該基於心跳間隔和節點之間的平均 RTT 值。選舉超時必須至少是 RTT 10 倍的時間以便對網絡波動。例如,如果 RTT 的值是 10 毫秒,那么選舉超時時間必須至少是 100 毫秒。選舉超時時間的上線是 50000 毫秒(50 秒),這個時間只能只用於全球范圍內分布式部署的 Etcd 集群。美國大陸的一個 RTT 的合理時間大約是 130 毫秒,美國和日本的 RTT 大約是 350~400 毫秒。如果算上網絡波動和重試的時間,那么 5 秒是一次全球 RTT 的安全上線。因為選舉超時時間應該是心跳包廣播時間的 10 倍,所以 50 秒的選舉超時時間是全局分布式部署 Etcd 的合理上線值。

心跳間隔和選舉超時時間的值對同一個 Etcd 集群的所有節點都生效,如果各個節點都不同的話,就會導致集群發生不可預知的不穩定性。Etcd 啟動時通過傳入啟動參數或環境變量覆蓋默認值,單位是毫秒。示例代碼具體如下:

$ etcd --heartbeat-interval=100 --election-timeout=500

# 環境變量值
$ ETCD_HEARTBEAT_INTERVAL=100 ETCD_ELECTION_TIMEOUT=500 etcd

快照

Etcd 總是向日志文件中追加 key,這樣一來,日志文件會隨着 key 的改動而線性增長。當 Etcd 集群使用較少時,保存完整的日志歷史記錄是沒問題的,但如果 Etcd 集群規模比較大時,那么集群就會攜帶很大的日志文件。為了避免攜帶龐大的日志文件,Etcd 需要做周期性的快照。快照提供了一種通過保存系統的當前狀態並移除舊日志文件的方式來壓縮日志文件。

快照調優

為 v2 后端存儲創建快照的代價是很高的,所以只用當參數累積到一定的數量時,Etcd 才會創建快照文件。默認情況下,修改數量達到 10000 時才會建立快照。如果 Etcd 的內存使用和磁盤使用過高,那么應該嘗試調低快照觸發的閾值,具體請參考如下命令。

啟動參數:

$ etcd --snapshot-count=5000

環境變量:

$ ETCD_SNAPSHOT_COUNT=5000 etcd

磁盤

etcd 的存儲目錄分為 snapshot 和 wal,他們寫入的方式是不同的,snapshot 是內存直接 dump file。而 wal 是順序追加寫,對於這兩種方式系統調優的方式是不同的,snapshot 可以通過增加 io 平滑寫來提高磁盤 io 能力,而 wal 可以通過降低 pagecache 的方式提前寫入時序。因此對於不同的場景,可以考慮將 snap 與 wal 進行分盤,放在兩塊 SSD 盤上,提高整體的 IO 效率,這種方式可以提升 etcd 20% 左右的性能。

etcd 集群對磁盤 I/O 的延時非常敏感,因為 Etcd 必須持久化它的日志,當其他 I/O 密集型的進程也在占用磁盤 I/O 的帶寬時,就會導致 fsync 時延非常高。這將導致 Etcd 丟失心跳包、請求超時或暫時性的 Leader 丟失。這時可以適當為 Etcd 服務賦予更高的磁盤 I/O 權限,讓 Etcd 更穩定的運行。在 Linux 系統中,磁盤 I/O 權限可以通過 ionice 命令進行調整。

nux 默認 IO 調度器使用 CFQ 調度算法,支持用 ionice 命令為程序指定 IO 調度策略和優先級,IO 調度策略分為三種:

  • Idle :其他進程沒有磁盤 IO 時,才進行磁盤 IO
  • Best Effort:缺省調度策略,可以設置 0-7 的優先級,數值越小優先級越高,同優先級的進程采用 round-robin 算法調度;
  • Real Time :立即訪問磁盤,無視其它進程 IO
  • None 即 Best Effort,進程未指定策略和優先級時顯示為 none,會使用依據 cpu nice 設置計算出優先級

Linux 中 etcd 的磁盤優先級可以使用 ionice 配置:

$ ionice -c2 -n0 -p `pgrep etcd`

網絡

etcd 中比較復雜的是網絡的調優,因此大量的網絡請求會在 peer 節點之間轉發,而且整體網絡吞吐也很大,但是還是再次強調不建議大家調整系統參數,大家可以通過修改 etcd 的 --heartbeat-interval--election-timeout 啟動參數來適當提高高吞吐網絡下 etcd 的集群魯棒性,通常同步吞吐在 100MB 左右的集群可以考慮將 --heartbeat-interval 設置為 300ms-500ms,--election-timeout 可以設置在 5000ms 左右。此外官方還有基於 TC 的網絡優先傳輸方案,也是一個比較適用的調優手段。

如果 etcd 的 Leader 服務大量並發客戶端,這就會導致 follower 的請求的處理被延遲因為網絡延遲。follower 的 send buffer 中能看到錯誤的列表,如下所示:

dropped MsgProp to 247ae21ff9436b2d since streamMsg's sending buffer is full

dropped MsgAppResp to 247ae21ff9436b2d since streamMsg's sending buffer is full

 

這些錯誤可以通過提高 Leader 的網絡優先級來提高 follower 的請求的響應。可以通過流量控制機制來提高:

// 針對 2379、2380 端口放行
$ tc qdisc add dev eth0 root handle 1: prio bands 3
$ tc filter add dev eth0 parent 1: protocol ip prio 1 u32 match ip sport 2380 0xffff flowid 1:1
$ tc filter add dev eth0 parent 1: protocol ip prio 1 u32 match ip dport 2380 0xffff flowid 1:1
$ tc filter add dev eth0 parent 1: protocol ip prio 2 u32 match ip sport 2379 0xffff flowid 1:1
$ tc filter add dev eth0 parent 1: protocol ip prio 2 u32 match ip dport 2379 0xffff flowid 1:1
 // 查看現有的隊列 
$ tc -s qdisc ls dev enp0s8
qdisc prio 1: root refcnt 2 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
 Sent 258578 bytes 923 pkt (dropped 0, overlimits 0 requeues 0)
 backlog 0b 0p requeues 0
 // 刪除隊列
$ tc qdisc del dev enp0s8 root 

數據規模

etcd 的硬盤存儲上限(默認是 2GB), 當 etcd 數據量超過默認 quota 值后便不再接受寫請求,可以通過設置 --quota-backend-bytes 參數來增加存儲大小,quota-backend-bytes 默認值為 0,即使用默認 quota 為 2GB,上限值為 8 GB,具體說明可參考官方文檔:https://github.com/etcd-io/etcd/blob/master/Documentation/dev-guide/limit.md 。

The default storage size limit is 2GB, configurable with `--quota-backend-bytes` flag. 8GB is a suggested maximum size for normal environments and etcd warns at startup if the configured value exceeds it. 

以下摘自 當 K8s 集群達到萬級規模,阿里巴巴如何解決系統各組件性能問題?

阿里進行了深入研究了 etcd 內部的實現原理,並發現了影響 etcd 擴展性的一個關鍵問題在底層 bbolt db 的 page 頁面分配算法上:隨着 etcd 中存儲的數據量的增長,bbolt db 中線性查找 “連續長度為 n 的 page 存儲頁面” 的性能顯著下降。 為了解決該問題,我們設計了基於 segregrated hashmap 的空閑頁面管理算法,hashmap 以連續 page 大小為 key, 連續頁面起始 page id 為 value。通過查這個 segregrated hashmap 實現 O(1) 的空閑 page 查找,極大地提高了性能。在釋放塊時,新算法嘗試和地址相鄰的 page 合並,並更新 segregrated hashmap。更詳細的算法分析可以見已發表在 CNCF 博客的博文。 通過這個算法改進,我們可以將 etcd 的存儲空間從推薦的 2GB 擴展到 100GB,極大地提高了 etcd 存儲數據的規模,並且讀寫無顯著延遲增長。 pull request :https://github.com/etcd-io/bbolt/pull/141

目前社區已發布的 v3.4 系列版本並沒有說明支持數據規模可達 100 G。

2.

etcd 性能測試

測試環境:本機 mac 使用 virtualbox 安裝 vm,所有 etcd 實例都是運行在在 vm 中的 docker 上

參考官方文檔:https://github.com/etcd-io/etcd/blob/master/Documentation/op-guide/performance.md

安裝 etcd 壓測工具 benchmark

1. // 下載benchmarck包
$ go get go.etcd.io/etcd/tools/benchmark
2. // 將benchmarck二進制文件放在gopath目錄下

3. // 驗證是否安裝成功
$ benchmark // 會顯示help信息

本文僅對 etcd v3.3.10 以及 v3.4.1 進行壓測。

寫入測試

# write to leader
benchmark --endpoints=${HOST_1} --target-leader --conns=1 --clients=1 \
    put --key-size=8 --sequential-keys --total=10000 --val-size=256
benchmark --endpoints=${HOST_1} --target-leader  --conns=100 --clients=1000 \
    put --key-size=8 --sequential-keys --total=100000 --val-size=256

# write to all members
benchmark --endpoints=${HOST_1},${HOST_2},${HOST_3} --conns=100 --clients=1000 \
    put --key-size=8 --sequential-keys --total=100000 --val-size=256

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM