TIDB 優化--TiKV 性能參數調優

TiKV 最底層使用的是 RocksDB 做爲持久化存儲,所以 TiKV 的很多性能相關的參數都是與 RocksDB 相關的。TiKV 使用了兩個 RocksDB 實例,默認 RocksDB 實例存儲 KV 數據,Raft RocksDB 實例(簡稱 RaftDB)存儲 Raft 數據。

TiKV 使用了 RocksDB 的 Column Falimies 特性。

默認 RocksDB 實例將 KV 數據存儲在內部的 defaultwrite 和 lock 3 個 CF 內。

  • default CF 存儲的是真正的數據,與其對應的參數位於 [rocksdb.defaultcf] 項中;
  • write CF 存儲的是數據的版本信息(MVCC)以及索引相關的數據,相關的參數位於 [rocksdb.writecf] 項中;
  • lock CF 存儲的是鎖信息,系統使用默認參數。

Raft RocksDB 實例存儲 Raft log。

  • default CF 主要存儲的是 raft log,與其對應的參數位於 [raftdb.defaultcf] 項中。

每個 CF 都有單獨的 block-cache,用於緩存數據塊,加速 RocksDB 的讀取速度,block-cache 的大小通過參數 block-cache-size 控制,block-cache-size 越大,能夠緩存的熱點數據越多,對讀取操作越有利,同時佔用的系統內存也會越多。

每個 CF 有各自的 write-buffer,大小通過 write-buffer-size 控制。

參數說明

# 日誌級別,可選值爲:trace,debug,info,warn,error,off
log-level = "info"

[server]
# 監聽地址
# addr = "127.0.0.1:20160"

# 建議使用默認值
# notify-capacity = 40960
# messages-per-tick = 4096

# gRPC 線程池大小
# grpc-concurrency = 4
# TiKV 每個實例之間的 gRPC 連接數
# grpc-raft-conn-num = 10

# TiDB 過來的大部分讀請求都會發送到 TiKV 的 coprocessor 進行處理,該參數用於設置
# coprocessor 線程的個數,如果業務是讀請求比較多,增加 coprocessor 的線程數,但應比系統的
# CPU 核數小。例如:TiKV 所在的機器有 32 core,在重讀的場景下甚至可以將該參數設置爲 30。在沒有
# 設置該參數的情況下,TiKV 會自動將該值設置爲 CPU 總核數乘以 0.8。
# end-point-concurrency = 8

# 可以給 TiKV 實例打標籤,用於副本的調度
# labels = {zone = "cn-east-1", host = "118", disk = "ssd"}

[storage]
# 數據目錄
# data-dir = "/tmp/tikv/store"

# 通常情況下使用默認值就可以了。在導數據的情況下建議將該參數設置爲 1024000。
# scheduler-concurrency = 102400
# 該參數控制寫入線程的個數,當寫入操作比較頻繁的時候,需要把該參數調大。使用 top -H -p tikv-pid
# 發現名稱爲 sched-worker-pool 的線程都特別忙,這個時候就需要將 scheduler-worker-pool-size
# 參數調大,增加寫線程的個數。
# scheduler-worker-pool-size = 4

[pd]
# pd 的地址
# endpoints = ["127.0.0.1:2379","127.0.0.2:2379","127.0.0.3:2379"]

[metric]
# 將 metrics 推送給 Prometheus pushgateway 的時間間隔
interval = "15s"
# Prometheus pushgateway 的地址
address = ""
job = "tikv"

[raftstore]
# 默認爲 true,表示強制將數據刷到磁盤上。如果是非金融安全級別的業務場景,建議設置成 false,
# 以便獲得更高的性能。
sync-log = true

# Raft RocksDB 目錄。默認值是 [storage.data-dir] 的 raft 子目錄。
# 如果機器上有多塊磁盤,可以將 Raft RocksDB 的數據放在不同的盤上,提高 TiKV 的性能。
# raftdb-dir = "/tmp/tikv/store/raft"

region-max-size = "384MB"
# region 分裂閾值
region-split-size = "256MB"
# 當 region 寫入的數據量超過該閾值的時候,TiKV 會檢查該 region 是否需要分裂。爲了減少檢查過程
# 中掃描數據的成本,數據過程中可以將該值設置爲32MB,正常運行狀態下使用默認值即可。
region-split-check-diff = "32MB"

[rocksdb]
# RocksDB 進行後臺任務的最大線程數,後臺任務包括 compaction 和 flush。具體 RocksDB 爲什麼需要進行 compaction,
# 請參考 RocksDB 的相關資料。在寫流量比較大的時候(例如導數據),建議開啓更多的線程,
# 但應小於 CPU 的核數。例如在導數據的時候,32 核 CPU 的機器,可以設置成 28。
# max-background-jobs = 8

# RocksDB 能夠打開的最大文件句柄數。
# max-open-files = 40960

# RocksDB MANIFEST 文件的大小限制.
# 更詳細的信息請參考:https://github.com/facebook/rocksdb/wiki/MANIFEST
max-manifest-file-size = "20MB"

# RocksDB write-ahead logs 目錄。如果機器上有兩塊盤,可以將 RocksDB 的數據和 WAL 日誌放在
# 不同的盤上,提高 TiKV 的性能。
# wal-dir = "/tmp/tikv/store"

# 下面兩個參數用於怎樣處理 RocksDB 歸檔 WAL。
# 更多詳細信息請參考:https://github.com/facebook/rocksdb/wiki/How-to-persist-in-memory-RocksDB-database%3F
# wal-ttl-seconds = 0
# wal-size-limit = 0

# RocksDB WAL 日誌的最大總大小,通常情況下使用默認值就可以了。
# max-total-wal-size = "4GB"

# 可以通過該參數打開或者關閉 RocksDB 的統計信息。
# enable-statistics = true

# 開啓 RocksDB compaction 過程中的預讀功能,如果使用的是機械磁盤,建議該值至少爲2MB。
# compaction-readahead-size = "2MB"

[rocksdb.defaultcf]
# 數據塊大小。RocksDB 是按照 block 爲單元對數據進行壓縮的,同時 block 也是緩存在 block-cache
# 中的最小單元(類似其他數據庫的 page 概念)。
block-size = "64KB"

# RocksDB 每一層數據的壓縮方式,可選的值爲:no,snappy,zlib,bzip2,lz4,lz4hc,zstd。
# no:no:lz4:lz4:lz4:zstd:zstd 表示 level0 和 level1 不壓縮,level2 到 level4 採用 lz4 壓縮算法,
# level5 和 level6 採用 zstd 壓縮算法,。
# no 表示沒有壓縮,lz4 是速度和壓縮比較爲中庸的壓縮算法,zlib 的壓縮比很高,對存儲空間比較友
# 好,但是壓縮速度比較慢,壓縮的時候需要佔用較多的 CPU 資源。不同的機器需要根據 CPU 以及 I/O 資
# 源情況來配置怎樣的壓縮方式。例如:如果採用的壓縮方式爲"no:no:lz4:lz4:lz4:zstd:zstd",在大量
# 寫入數據的情況下(導數據),發現系統的 I/O 壓力很大(使用 iostat 發現 %util 持續 100% 或者使
# 用 top 命令發現 iowait 特別多),而 CPU 的資源還比較充裕,這個時候可以考慮將 level0 和
# level1 開啓壓縮,用 CPU 資源換取 I/O 資源。如果採用的壓縮方式
# 爲"no:no:lz4:lz4:lz4:zstd:zstd",在大量寫入數據的情況下,發現系統的 I/O 壓力不大,但是 CPU
# 資源已經吃光了,top -H 發現有大量的 bg 開頭的線程(RocksDB 的 compaction 線程)在運行,這
# 個時候可以考慮用 I/O 資源換取 CPU 資源,將壓縮方式改成"no:no:no:lz4:lz4:zstd:zstd"。總之,目
# 的是爲了最大限度地利用系統的現有資源,使 TiKV 的性能在現有的資源情況下充分發揮。
compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"]

# RocksDB memtable 的大小。
write-buffer-size = "128MB"

# 最多允許幾個 memtable 存在。寫入到 RocksDB 的數據首先會記錄到 WAL 日誌裏面,然後會插入到
# memtable 裏面,當 memtable 的大小到達了 write-buffer-size 限定的大小的時候,當前的
# memtable 會變成只讀的,然後生成一個新的 memtable 接收新的寫入。只讀的 memtable 會被
# RocksDB 的 flush 線程(max-background-flushes 參數能夠控制 flush 線程的最大個數)
# flush 到磁盤,成爲 level0 的一個 sst 文件。當 flush 線程忙不過來,導致等待 flush 到磁盤的
# memtable 的數量到達 max-write-buffer-number 限定的個數的時候,RocksDB 會將新的寫入
# stall 住,stall 是 RocksDB 的一種流控機制。在導數據的時候可以將 max-write-buffer-number
# 的值設置的更大一點,例如 10。
max-write-buffer-number = 5

# 當 level0 的 sst 文件個數到達 level0-slowdown-writes-trigger 指定的限度的時候,
# RocksDB 會嘗試減慢寫入的速度。因爲 level0 的 sst 太多會導致 RocksDB 的讀放大上升。
# level0-slowdown-writes-trigger 和 level0-stop-writes-trigger 是 RocksDB 進行流控的
# 另一個表現。當 level0 的 sst 的文件個數到達 4(默認值),level0 的 sst 文件會和 level1 中
# 有 overlap 的 sst 文件進行 compaction,緩解讀放大的問題。
level0-slowdown-writes-trigger = 20

# 當 level0 的 sst 文件個數到達 level0-stop-writes-trigger 指定的限度的時候,RocksDB 會
# stall 住新的寫入。
level0-stop-writes-trigger = 36

# 當 level1 的數據量大小達到 max-bytes-for-level-base 限定的值的時候,會觸發 level1 的
# sst 和 level2 種有 overlap 的 sst 進行 compaction。
# 黃金定律:max-bytes-for-level-base 的設置的第一參考原則就是保證和 level0 的數據量大致相
# 等,這樣能夠減少不必要的 compaction。例如壓縮方式爲"no:no:lz4:lz4:lz4:lz4:lz4",那麼
# max-bytes-for-level-base 的值應該是 write-buffer-size 的大小乘以 4,因爲 level0 和
# level1 都沒有壓縮,而且 level0 觸發 compaction 的條件是 sst 的個數到達 4(默認值)。在
# level0 和 level1 都採取了壓縮的情況下,就需要分析下 RocksDB 的日誌,看一個 memtable 的壓
# 縮成一個 sst 文件的大小大概是多少,例如 32MB,那麼 max-bytes-for-level-base 的建議值就應
# 該是 32MB * 4 = 128MB。
max-bytes-for-level-base = "512MB"

# sst 文件的大小。level0 的 sst 文件的大小受 write-buffer-size 和 level0 採用的壓縮算法的
# 影響,target-file-size-base 參數用於控制 level1-level6 單個 sst 文件的大小。
target-file-size-base = "32MB"

# 在不配置該參數的情況下,TiKV 會將該值設置爲系統總內存量的 40%。如果需要在單個物理機上部署多個
# TiKV 節點,需要顯式配置該參數,否則 TiKV 容易出現 OOM 的問題。
# block-cache-size = "1GB"

[rocksdb.writecf]
# 保持和 rocksdb.defaultcf.compression-per-level 一致。
compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"]

# 保持和 rocksdb.defaultcf.write-buffer-size 一致。
write-buffer-size = "128MB"
max-write-buffer-number = 5
min-write-buffer-number-to-merge = 1

# 保持和 rocksdb.defaultcf.max-bytes-for-level-base 一致。
max-bytes-for-level-base = "512MB"
target-file-size-base = "32MB"

# 在不配置該參數的情況下,TiKV 會將該值設置爲系統總內存量的 15%。如果需要在單個物理機上部署多個
# TiKV 節點,需要顯式配置該參數。版本信息(MVCC)相關的數據以及索引相關的數據都記錄在 write 這
# 個 cf 裏面,如果業務的場景下單表索引較多,可以將該參數設置的更大一點。
# block-cache-size = "256MB"

[raftdb]
# RaftDB 能夠打開的最大文件句柄數。
# max-open-files = 40960

# 可以通過該參數打開或者關閉 RaftDB 的統計信息。
# enable-statistics = true

# 開啓 RaftDB compaction 過程中的預讀功能,如果使用的是機械磁盤,建議該值至少爲2MB。
# compaction-readahead-size = "2MB"

[raftdb.defaultcf]
# 保持和 rocksdb.defaultcf.compression-per-level 一致。
compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"]

# 保持和 rocksdb.defaultcf.write-buffer-size 一致。
write-buffer-size = "128MB"
max-write-buffer-number = 5
min-write-buffer-number-to-merge = 1

# 保持和 rocksdb.defaultcf.max-bytes-for-level-base 一致。
max-bytes-for-level-base = "512MB"
target-file-size-base = "32MB"

# 通常配置在 256MB 到 2GB 之間,通常情況下使用默認值就可以了,但如果系統資源比較充足可以適當調大點
block-cache-size = "256MB"

TiKV 內存使用情況

除了以上列出的 block-cache 以及 write-buffer 會佔用系統內存外:

  1. 需預留一些內存作爲系統的 page cache
  2. TiKV 在處理大的查詢的時候(例如 select * from ...)會讀取數據然後在內存中生成對應的數據結構返回給 TiDB,這個過程中 TiKV 會佔用一部分內存

https://pingcap.com/docs-cn/op-guide/tune-tikv/

TIDB優化鏈接:https://pingcap.com/docs-cn/sql/server-command-option/

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