收到一個task,搭建3節(jié)點的tikv集群,用相關(guān)profiling工具研究下tikv可能的性能瓶頸,可暫時只測raw kv insert性能。
聽起來有些挑戰(zhàn)性。平常profile的多半是c/c++程序,這rust版本的程序還真沒弄過。對rust的了解,目前較淺顯,對tikv的了解非源碼級別上。Anyway,也并非不了解源碼就做不成,性能profiling過程大同小異,順便熟悉一下編譯安裝、監(jiān)控搭建等過程
tikv集群及監(jiān)控安裝
參照前一篇文章安裝。不過,有兩個問題。
-
若是不加修改使用pd.toml, tikv.toml,tikv的日志中一直有下圖所示的ERROR; 但用pd-ctl檢查狀態(tài)都是正常的(暫不確定為何,但貌似不影響測試)
image.png - 擔(dān)心latest中的binary沒有包含DEBUG符號信息,這樣在火焰圖可能會出現(xiàn)大量unknown,所以嘗試自己編譯tikv
編譯tikv release with debuginfo
切換到v3.0.0-beta分支,執(zhí)行cargo build --release(Cargo.toml默認debug=true; 默認并行編譯)??赡艿木幾gerror有:
- 若出現(xiàn)
error: expected ``)' before 'PRIu64',則export CXXFLAGS="-D__STDC_FORMAT_MACROS" - 若
unrecognized command line option ‘-Wimplicit-fallthrough’,則更新g++到7.x - 若
error: ‘google’ has not been declared,則手工編譯安裝gflags 2.2+
編譯耗時較長(24cores, > 30min)
比較target/release下的tikv-server與tidb-latest-linux-amd64/bin/tikv-server,竟然一樣大。只好認為binary包中的帶有debuginfo(也許可以從readelf -S tidb-latest-linux-amd64/bin/tikv-server | grep debug得知)
rust profiler
perf + flamegraph
平常perf用于分析C++程序性能用得較多,既然也可用于分析rust程序,本次實踐就用perf。
參考
http://carol-nichols.com/2015/12/09/rust-profiling-on-osx-cpu-time/
rust-lang post: Profiling in rust application
cargo profiler
它支持callgrind, cachegrind等valgrind系列工具,但其counting開銷要比perf_events的sampling大些;
當(dāng)然,valgrind也可單獨作用于rust 程序,如How-to Optimize Rust Programs on Linux 詳細介紹了使用valgrind工具來profiling rust program
flame + flamer
flame是原生的rust性能分析庫,不同于perf,它是通過給特定代碼加上instrumentation code,從而得到那部分代碼的火焰圖。有些類似于systemtap的探針;
flamer是給flame制作的編譯器插件,使用annotation更加方便地注入instrumentation code
benchmark tools: go-ycsb
指定了用https://github.com/pingcap/go-ycsb,這個由golang改寫的YCSB壓測工具,作者在go-ycsb:一個 Go 的 YCSB 移植也做了相關(guān)介紹。當(dāng)然有時間的話,也可以用java版本的YCSB,不過可能得另加tikv db 接口了。
編譯go-ycsb曲折小插曲:
本來想在開發(fā)機編譯go-ycsb,出現(xiàn)了unrecognized import path "golang.org/x/net"類似的問題后,就手動從github.com clone到golang.org/x文件夾內(nèi)。沒想到還是不行,猜測原因在于go.mod文件指定了依賴的特定版本,而我clone的時候默認是主版本。這一個一個clone有點麻煩,還是希望能編譯。
暫不知如何在公司機器上加科學(xué)上網(wǎng)的代理,于是考慮在個人windows上安裝virtualbox linux,借助windows上已經(jīng)配置成功的代理可橋接到golang.org/x, googleapis等,然而在某些地址上發(fā)生i/o timeout。額,最后一招了,借助公司windows上的virtualbox linux,終于可以編譯了,雖然中間也出現(xiàn)了uber.org的i/o timeout,手動從github下載相應(yīng)tag版本后就可以了。順便拷貝所有的pkg到開發(fā)機上
選擇一臺物理機(10.110.36.144)作壓測節(jié)點(與tikv node ping latency 1.4ms),執(zhí)行
./bin/go-ycsb shell tikv -p tikv.pd=http://10.16.148.72:2379 -p tikv.type=raw
出現(xiàn)錯誤
ERRO[0003] [pd] failed to get cluster id: rpc error: code = Unavailable desc = all SubConns are in TransientFailure, latest connection error: connection error: desc = "transport: Error while dialing failed to do connect handshake, response: "HTTP/1.0 403 Forbidden
弄了半天也沒發(fā)現(xiàn)哪里出了問題,pd, tikv-server都沒ERROR日志。只好去社區(qū)提了個issue #96。幾小時之后,細致地看錯誤信息后,發(fā)現(xiàn)有access denied, squid等字眼,懷疑是不是https_proxy被設(shè)置了,果然是它!
先嘗試跑個shell basic,

- 問題:當(dāng)?shù)诙芜M入shell命令行時,exit時出現(xiàn)報錯,這應(yīng)該不是個正確的行為。見issue #97,這個問題以后再跟蹤
空閑狀態(tài)下的火焰圖
下圖是tikv-1節(jié)點在空閑狀態(tài)下的火焰圖。可以看出tikv進程的線程還是蠻多的,用ps -L -p $(pidof tikv-server) | wc -l發(fā)現(xiàn)有194個,遠超邏輯CPU個數(shù)48。是否合理,合理到能平衡context-switch, lock contention所帶來的負面影響,值得探討。
由下圖可知,線程grpc_global_tim和transport_stats占了CPU大塊頭。(不明白為什么還是有unknown ?)

go-ycsb load phase
基本想法是:目前只有一臺物理機client loader,為看清server性能,client應(yīng)盡可能吃滿CPU(24 cores)
命令:
./bin/go-ycsb load tikv -P workloads/workloada -p tikv.pd=10.16.148.72:2379 -p tikv.type=raw -p recordcount=100000000 -p tikv.conncount=1024 -p tikv.batchsize=256
然而,
- 我以為dropdata=true是刪除tikv所有數(shù)據(jù),然而貌似沒有
- 我以為增加
tikv.conncount,可以提高客戶端的壓力,然而選1或1024,insert ops始終在1.7w; htop端顯示的CPU遠未得到利用 (那該如何增加單個go-ycsb實例的壓力呢?)
image.png
執(zhí)行 ./deploy perf,火焰圖如下:

- 線程rocksdb::low4占用了主要部分,其中compaction及壓縮占了很大部分,還有ext4 write; rocksdb選項有中
use-direct-io-for-flush-and-compaction,這個為何默認為false呢
image.png -
memory allocation火焰圖。各線程分配看似比較均勻, apply線程占得稍多;像std::string動態(tài)分配在rocksdb中好像很多,會有所影響
image.png
一小時后的監(jiān)控部分指標(biāo)截圖
grpc消息P99延時大概在23ms; 總共200G,每個tikv實例承擔(dān)了65G, raw_input只在1.5w。壓力不夠是個原因(要么再找go-ycsb提高CPU利用率的方法/參數(shù),要么增加多個go-ycsb實例)

go-ycsb run phase
run階段的workload種類豐富,由于時間關(guān)系,以后再來補充。此次目的是探一探raw kv insert的究竟,我想在load階段就可以體現(xiàn)出來。等熟悉參數(shù)后再做run階段的壓測
Summary
此次profiling還不是很深入,這么多參數(shù)搭配,還是需好好理解一番。不過從個人經(jīng)驗來講,有以下注意事項:
-
grpc-concurrency,end-point-concurrency等并發(fā)值該怎么配,與特定機器上的cores N如何適配?前面提到,啟動后的線程數(shù)有194個,它們?nèi)绾胃咝Ю肗需要研究; 且此次測試未發(fā)現(xiàn)go-ycsb單實例提高壓力的方法/參數(shù),所以默認并發(fā)為4的grpc poll cpu維持在40%以下,不太符合壓測吞吐量時的要求(將CPU打滿,至少是前臺grpc線程的CPU) - tikv默認應(yīng)該使用了jemalloc,動態(tài)分配是否盡可能采用預(yù)分配呢,以防止在hot path上受阻
- 最后面板可以再調(diào)整。參數(shù)眾多,雖說用了grafana panel的折疊功能,但是想看全貌還是得不斷地expand, scroll,不是很方便,刷新也容易遲緩。
- 我想應(yīng)該是可以通過建立模板變量,為不同component設(shè)置不同label,想看什么直接下拉選擇component name;
- 或者再加一個不同視圖的dashboard,比如rocksdb是一個視圖,raft是另外一個視圖,grpc也是,讓視圖之間互相引用鏈接,也不錯
- 若想按instance聚合而非job,則添加聚合變量為宜
rustasync社區(qū)有 issue #13談到了給rust添加shared-nothing的線程執(zhí)行器,類似seastar::future的異步機制。私以為這是個好消息,雖暫時還看不太懂里面討論的rust async原語,但future, lock-free, no context-switch等這些好處我認為在未來多核系統(tǒng)上將會展現(xiàn)充分。持續(xù)關(guān)注這個issue



