Go語言項目性能優化實例剖析

jopen 9年前發布 | 22K 次閱讀 Go語言

kingshard性能優化網絡篇

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

1. 發現kingshard的性能瓶頸

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

1.1 環境搭建

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

CPU: 2.2GHZ * 4
內存:16GB
硬盤: 256GB 

1.2 性能測試步驟

具體步驟如下所述:

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

go get github.com/davecheney/profile 

2.在工程內import這個組件

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

func main() {
  defer profile.Start(profile.CPUProfile).Stop()
  fmt.Print(banner)
  runtime.GOMAXPROCS(runtime.NumCPU())
  flag.Parse()
  ....
}

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

./bin/kingshard -config=etc/ks.yaml 

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

2015/10/31 10:28:06 profile: cpu profiling enabled, /var/folders/4q/zzb55sfj377b6vdyz2brt6sc0000gn/T/profile205276958/cpu.pprof

后面的路徑就是pprof性能分析文件的位置,Ctrl+C中斷服務器

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

sysbench --test=oltp --num-threads=16 --max-requests=160000 --oltp-test-mode=nontrx --db-driver=mysql --mysql-db=kingshard --mysql-host=127.0.0.1 --mysql-port=9696 --mysql-table-engine=innodb --oltp-table-size=10000 --mysql-user=kingshard --mysql-password=kingshard --oltp-nontrx-mode=select --db-ps-mode=disable run

得到如下結果:
OLTP test statistics:
  queries performed:
    read:                           160071
    write:                         0
    other:                         0
    total:                         160071
  transactions:                     160071 (16552.58 per sec.)
  deadlocks:                           0      (0.00 per sec.)
  read/write requests:               160071 (16552.58 per sec.)
  other operations:                 0     (0.00 per sec.)
Test execution summary:
  total time:                         9.6705s
  total number of events:             160071
  total time taken by event execution: 154.4474
  per-request statistics:
     min:                                 0.29ms
     avg:                                 0.96ms
     max:                                14.17ms
     approx.  95 percentile:               1.37ms
Threads fairness:
  events (avg/stddev):         10004.4375/24.95
  execution time (avg/stddev):   9.6530/0.00

  • 按照上述步驟測試三次(16552.58,16769.72,16550.16)取平均值,得到優化前kingshard的QPS是:16624.15

    </li>

  • 按照上述步驟,直連MySQL。測試直連MySQL的QPS,同樣測試三次QPS(27730.90,28499.05,27119.20),得到直連MySQL的QPS是:27783.05。

    </li>

  • 從上述數據可以計算出kingshard轉發SQL的性能是直連MySQL的59%左右。
  • </ul>

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

    8.調用go tool工具制作CPU耗時的PDF文檔

    go tool pprof -pdf ./kingshard cpu.pprof > report.pdf 

    2. 性能測試報告分析

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

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

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

    func (c *TCPConn) SetNoDelay(noDelay bool) error 

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

    2.1 代碼修改和性能測試

    發現了性能瓶頸以后,修改proxy/server/server.go文件中的newClientConn函數和backend /backend_conn.go中的ReConnect函數,分別設置client與kingshard之間的連接和kingshard到MySQL之間的連接為最小化傳輸延時。具體的代碼修改可以查看這個commit。

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

    OLTP test statistics:
      queries performed:
        read:                           160174
        write:                         0
        other:                         0
        total:                         160174
      transactions:                     160174 (21291.68 per sec.)
      deadlocks:                           0      (0.00 per sec.)
      read/write requests:               160174 (21291.68 per sec.)
      other operations:                 0     (0.00 per sec.)
    Test execution summary:
      total time:                         7.5228s
      total number of events:             160174
      total time taken by event execution: 119.9655
      per-request statistics:
         min:                                 0.26ms
         avg:                                 0.75ms
         max:                                10.78ms
         approx.  95 percentile:               1.13ms
    Threads fairness:
      events (avg/stddev):         10010.8750/38.65
      execution time (avg/stddev):   7.4978/0.00

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

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

    原文  https://github.com/flike/kingshard/blob/master/doc/KingDoc/kingshard_

     本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
     轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
     本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!