天天看點

【TiDB 最佳實踐系列】海量 Region 叢集調優

作者:張博康

在 TiDB 的架構中,所有的資料按照 range 劃分成一個個 Region 分布在多個 TiKV 執行個體上。随着資料的寫入,一個叢集中會産生上百萬,甚至千萬個 Region。而量變引起質變,單 TiKV 執行個體上過多的 Region 無疑會帶來比較大的負擔,進而影響整個叢集的性能表現。

本文将介紹 TiKV 核心子產品 Raftstore 的處理流程以使大家更好得了解海量 Region 導緻性能問題的根源,以及針對這種情況的一些優化手段。

Raftstore 的處理流程

大家都知道在一個 TiKV 執行個體上會有多個 Region,這些 Region 消息處理就是通過 Raftstore 這個子產品來驅動的,包括 Region 上讀寫請求的處理,Raft log 的持久化以及複制,還有 Raft 的心跳處理等等。為什麼 Region 數多了就會影響到整個叢集的性能呢?為了解釋這個問題,我們先來看看 TiKV 的核心子產品 Raftstore 是怎樣工作的。

​​

【TiDB 最佳實踐系列】海量 Region 叢集調優

​​

注:該示意圖僅僅表意,不代表代碼層面的實際結構。

上圖是 Raftstore 處理流程的示意圖,可以看到,從 TiDB 發來的請求會通過 gRPC 和 storage 子產品變成最終的 KV 讀寫消息發往相應的 Region,而這些消息并不會立即處理而是暫存下來。而在 Raftstore 中會輪詢檢查每個 Region 是否有需要處理的消息。如果有消息,那麼 Raftstore 會驅動 Raft 狀态機去處理這些消息,并根據這些消息所産生的狀态變更去完成一些後續動作。比如,在有寫請求時,Raft 狀态機需要将日志落盤并且将日志發送給其他副本;在達到心跳間隔時,Raft 狀态機需要将心跳資訊發送給其他副本。

性能問題及優化方法

從上面我們可以看到,這麼多 Region 的消息是一個接一個地處理。那麼在 Region 很多的情況下,Raftstore 會需要花費一些時間處理大量 Region 的心跳,勢必會引入一些延遲,導緻一些讀寫請求得不到特别及時的處理。如果在讀寫壓力大的情況下,很容易使得 Raftstore 線程 CPU 達到瓶頸,而延遲會被進一步放大,進而影響性能表現。

常見現象

一般來說,在有負載的情況下,如果 TiKV 的 Raftstore CPU 使用率達到了 85%+(指的是單線程的情況,多線程等比例放大),我們就認為 Raftstore 已經達到了比較繁忙的狀态成為了瓶頸(由于 Raftstore 線程中有 IO 操作,是以 CPU 使用率不可能達到 100%),同時 propose wait duration 可能會達到百毫秒級别。

相關 metrics 可在 TiKV grafana 面闆下檢視:

  • Thread-CPU 下的 Raftstore CPU

參考值:最好低于 ​

​raftstore.store-pool-size * 85%​

​​ (v2.1 版本中無此配置項,可認為 ​

​raftstore.store-pool-size = 1​

​ )。

​​

【TiDB 最佳實踐系列】海量 Region 叢集調優

​​

  • Raft Propose 下的 Propose wait duration

Propose wait duration 是發送請求給 Raftstore、到 Raftstore 真正處理請求之間的延遲。如果該延遲比較長,說明 Raftstore 比較繁忙或者 append log 比較耗時導緻 Raftstore 不能及時處理請求。

參考值:最好低于 50-100ms。

​​

【TiDB 最佳實踐系列】海量 Region 叢集調優

​​

優化方法

既然我們已經知道了性能問題的根源,那麼就可以從兩方面入手:減少單個 TiKV 執行個體的 Region 數;減少單個 Region 的消息數。

根據不同版本,具體可以參考以下優化方法:

v2.1 版本

在 v2.1 版本中 Raftstore 隻能是單線程,是以一般在 Region 數超過 10 萬時就會逐漸成為瓶頸。

  1. 增加 TiKV 執行個體

如果 IO 資源和 CPU 資源都還有比較多的盈餘的話,可以在單個機器上部署多個 TiKV 執行個體,以減少單個 TiKV 執行個體上的 Region 個數,或者擴容叢集的 TiKV 機器數。

  1. 開啟 Region Merge

另外一種可以減少 Region 個數的辦法是開啟 Region Merge。與 Region Split 相反,Region Merge 是通過排程把相鄰的小 Region 合并的過程。在叢集有删除資料或者進行過 Drop Table/Truncate Table 後,可以将那些小 Region 甚至空 Region 進行合并以減少資源的消耗。

簡單來說,通過 pd-ctl 設定相關參數即可開啟 Region Merge

>> pd-ctl config set max-merge-region-size 20>> pd-ctl config set max-merge-region-keys 200000>> pd-ctl config set merge-schedule-limit 8      

關于更多詳情請參考這兩個文檔 如何配置 Region Merge 和 PD 配置檔案描述,在此不再展開。

同時,預設配置的 Region Merge 預設參數設定相對保守,可以根據需求參考​​《TiDB 最佳實踐系列(二)PD 排程政策》​​ 中提及的具體方法加快 Region Merge 速度。

  1. 調整 raft-base-tick-interval

除了減小 Region 個數,我們還可以通過盡量減少 Region 機關時間内的消息數量以減小 Raftstore 壓力。比如,在 TiKV 配置中适當增大 raft-base-tick-interval :

[raftstore]raft-base-tick-interval = “2s”      

​raft-base-tick-interval​

​ 是 Raftstore 驅動每個 Region 的 Raft 狀态機的基本時間機關,也就是每隔這麼久就需要向 Raft 狀态機發送一個 tick 消息。顯然增大這個時間間隔,可以有效減少 Raftstore 消息數量。

需要注意的是,這個 tick 也決定了 election timeout 和 heartbeat 的間隔。

raft-election-timeout = raft-base-tick-interval * raft-election-timeout-ticksraft-heartbeat-interval = raft-base-tick-interval * raft-heartbeat-ticks      

follower 在 ​

​raft-election-timeout​

​​ 間隔内未收到來自 leader 的心跳會認為 leader 出現故障而發起新的選舉,而 ​

​raft-heartbeat-interval​

​​ 是 leader 向 follower 發送心跳的間隔,是以增大 ​

​raft-base-tick-interval​

​ 可以減少機關時間内 Raft 發送的網絡消息,但也會讓 Raft 檢測到 leader 故障的時間更長。

v3.0 版本

除了以上提及的優化方法外(注:Region Merge 在 v3.0 版本中預設開啟),v3.0 版本中還可以進行以下優化:

  1. 提高 Raftstore 并發數

在 v3.0 版本中 Raftstore 已經擴充為多線程,極大降低了 Raftstore 線程成為瓶頸的可能性。

預設 TiKV 配置 ​

​raftstore.store-pool-size​

​ 為 2,如果在 Raftstore 出現瓶頸的時候可以根據實際情況适當提高,但不建議設定過大以防引入不必要的線程切換開銷。

  1. 開啟 Hibernate Region

在實際情況下,讀寫請求并不會均勻的打在每個 Region 上,而是主要集中在少數的 Region 上,那麼對于暫時空閑的 Region 我們是不是可以盡量減少它們的消息數量。這也就是 Hibernate Region 的主要思想,在無必要的時候不進行 ​

​raft-base-tick​

​ ,也就是不去驅動那些空閑 Region 的 Raft 狀态機,那麼就不會觸發這些 Region 的 Raft 心跳資訊的産生,極大得減小了 Raftstore 的工作負擔。

截止發稿時 Hibernate Region 還是一個實驗 feature,在 master 上已經預設開啟。如有需要,可酌情開啟,相關配置說明請參考 配置 Hibernate Region。

其他可能出現的問題

PD Leader 切換慢

PD 需要将 Region Meta 資訊持久化在 etcd 以保證 PD Leader 節點切換後能快速繼續提供 Region 路由服務。随着 Region 數量的增長,Etcd 的性能問題會使得 PD 在切換 Leader 時從 etcd 擷取這些資訊時比較慢,在百萬 Region 量級時可能達到十幾秒甚至幾十秒。

是以在 v3.0 版本中 PD 将 Region Meta 資訊存在本地的 LevelDB 中,通過另外的機制同步 PD 節點間的資訊。

在 v3.0 版本中 PD 已經預設開啟配置 ​

​use-region-storage​

​ ,而 v2.1 版本如碰到類似問題建議更新到 v3.0。

PD 路由資訊更新 不及時

在 TiKV 中是由 pd-worker 這個子產品來将 Region Meta 資訊定期上報給 PD,在 TiKV 重新開機或者 Region Leader 切換時需要通過統計資訊重新計算 Region 的 ​

​approximate size/keys​

​ 。那麼在 Region 數量比較多的情況下,pd-worker 單線程可能成為瓶頸,造成任務的堆積不能及時處理,是以 PD 不能及時擷取某些 Region Meta 資訊以緻路由資訊更新不及時。該問題不會影響實際的讀寫,但可能導緻 PD 排程的不準确以及 TiDB 更新 region cache 時需要多幾次 round-trip。

可以在 TiKV grafana 面闆中檢視 Task 下的 Worker pending tasks 來确定 pd-worker 是否有任務堆積,正常來說 pending tasks 應該維持在一個比較低的值。

​​

【TiDB 最佳實踐系列】海量 Region 叢集調優

​​

我們在 master 上已經對 pd-worker 進行了效率優化,預計會在 v2.1.19 和 v3.0.5 中帶上相關優化,如碰到類似問題建議更新。

Prometheus 慢查詢

在大規模叢集中,TiKV 執行個體數的增加會讓 Prometheus 的查詢時的計算壓力較大導緻 Grafana 檢視 metrics 時較慢,在 v3.0 版本中通過設定了一些 metrics 的預計算有所緩解。

總結

上一篇: JMS基礎
下一篇: JMS入門

繼續閱讀