天天看點

Go語言項目(kingshard)性能優化執行個體剖析

最近kingshard的功能開發節奏慢了許多。一方面是工作确實比較忙,另一方面是我覺得kingshard的功能已經比較完善了,下一步的開發重點應該是性能優化。畢竟作為一個mysql proxy,如果轉發sql的性能很差,再多的功能都無濟于事。是以這個周末一直宅在家裡優化kingshard的轉發性能。經過兩天的探索發現,将kingshard的轉發sql性能提升了18%左右,在這個過程中學到了一下知識。借此機會分享一下,同時也是督促一下自己寫部落格的積極性。:)

首選,對kingshard進行性能優化,我們必須要找到kingshard的性能瓶頸在哪裡。go語言在性能優化支援方面做的非常好,借助于go語言的pprof工具,我們可以通過簡單的幾個步驟,就能得到kingshard在轉發sql請求時的各個函數耗時情況。

根據kingshard使用指南搭建一個kingshard代理環境。我是用macbook搭建的環境,硬體參數如下所示:

具體步驟如下所述:

1.擷取一個性能分析的封裝庫

2.在工程内import這個元件

3.在kingshard/cmd/kingshard/main.go的main函數開始部分添加cpu監控的啟動和停止入口

4.重新編譯工程, 運作kingshard

5.kingshard啟動後會在終端輸出下面一段提示:

後面的路徑就是pprof性能分析檔案的位置,ctrl+c中斷伺服器

6.這時候用sysbench對kingshard進行壓力測試,得到qps(有關sysbench的安裝和使用,請自行google解決)。具體的代碼如下所示:

得到如下結果:

7.将cpu.prof拷貝到bin/kingshard所在位置

8.調用go tool工具制作cpu耗時的pdf文檔

通過上述指令,可以生成壓測期間主要函數耗時情況。從report來看,主要的耗時在tcp層資料包的收發上面。那我們應該主要考慮如何優化tcp層資料的收發方面。優化tcp傳輸效率,我首先想到了減少系統調用,每個資料包傳輸盡量多的資料。

在通過 tcp socket 進行通信時,資料都拆分成了資料塊,這樣它們就可以封裝到給定連接配接的 tcp payload(指 tcp 資料包中的有效負荷)中了。tcp payload 的大小取決于幾個因素(例如最大封包長度和路徑),但是這些因素在連接配接發起時都是已知的。為了達到最好的性能,我們的目标是使用盡可能多的可用資料來填充每個封包。當沒有足夠的資料來填充 payload 時(也稱為最大封包段長度(maximum segment size) 或 mss),tcp 就會采用 nagle 算法自動将一些小的緩沖區連接配接到一個封包段中。這樣可以通過最小化所發送的封包的數量來提高應用程式的效率,并減輕整體的網絡擁塞問題。

由于這種算法對資料進行合并,試圖構成一個完整的 tcp 封包段,是以它會引入一些延時。但是這種算法可以最小化線上路上發送的封包的數量,是以可以最小化網絡擁塞的問題。但是在需要最小化傳輸延時的情況中,go語言中sockets api 可以提供一種解決方案。就是通過:

這個函數在go中預設情況下,是設定為true,也就是未開啟延遲選項。我們需要将其設定為false選項,來達到每個資料包傳輸盡量多的資料,減少系統調用的目的。

發現了性能瓶頸以後,修改proxy/server/server.go檔案中的newclientconn函數和backend/backend_conn.go中的reconnect函數,分别設定client與kingshard之間的連接配接和kingshard到mysql之間的連接配接為最小化傳輸延時。具體的代碼修改可以檢視這個commit。

修改後我們利用sysbench重新測試,測試指令和上述測試一緻。得到的結果如下所示:

測試三次得到的qps為:21291.68,21670.85,21463.44。 相當于直連mysql性能的77%左右,通過這個優化性能提升了18%左右。

通過這篇文章,介紹了通過go語言提供的pprof對kingshard進行性能分析的詳細步驟。對于其他go語言項目也可以通過類似步驟生成性能報告文檔。性能優化的關鍵是發現性能瓶頸,再去找優化方案。有時候簡單的優化,就可以達到預想不到的效果,希望本文能給go開發者在性能優化方面提供一個思路。最後打個廣告:kingshard作為一個支援sharding的開源mysql中間件項目,目前已經比較穩定了,且經過性能優化後,轉發sql的性能提升了不少。後續我還會在鎖和記憶體方面對kingshard進行優化,敬請期待。