前言
辛苦開發了一年的服務,終于要上線了,進入了關鍵的質檢階段--壓力測試環節。
目標值:一千個用戶,300rps
問題
因開發節奏的緊張,初期并沒有注重優化,果不其然,一壓測就爆炸了,主要問題有如下:
- RPS太低,1000個用戶下,rps初期僅100
- 隨著時間的推移,rps逐步降低
- 服務器隨時閃崩
很明顯,壓測后感覺我們的代碼是一坨樂色,還能咋辦呢,慢慢排查吧。
思考
1.服務器為什么會崩潰?
2.為什么請求的響應耗時很奇怪,時而快時而慢(且多次隨著時間的推移 響應越來越慢)?
3.rps為什么那么低?瓶頸點在哪里?如何優化?
4.某些業務,沒有復雜業務邏輯,卻耗時較高,且不穩定
排查過程
- 服務器突然崩掉,必須優先排查,為什么崩掉呢?
- 資源不足,如cpu 內存等資源不足,導致服務太卡頓或內存溢出
1.考慮壓測服務本身是和其他服務共用資源,導致壓測數據有波動(時而快時而慢),內存不足導致崩潰 2.內存泄露,導致壓測后期崩掉,內存不足導致崩潰(通過pprof排查) 3.排查過程中,因埋點太多,導致日志發送太多,因公司的日志組件實現,若不能及時發送到遠程,會堆積在本地,則導致本地磁盤占滿,服務器打開了太多文件句柄,導致內存溢出.(后提出優化,若磁盤占用一定大小,則先刪舊的文件,再寫入新文件)
- 協程沒有捕獲panic
最常見的服務崩潰,但排查后發現,無論是異步業務,或者普通請求,都有捕獲,并不是該原因
- 并發問題
代碼很難看出來,經過多次排查日志,發現部分崩潰原因是因為未對map加鎖(盡量使用sync.map)
- 資源不足,如cpu 內存等資源不足,導致服務太卡頓或內存溢出
- rps 太低,(大部分業務耗時都大于300毫秒),那原因何在?
- 可能是業務邏輯錯誤,混亂,導致問題。
排查方向,寫一個中間件工具,針對壓測結果,出錯業務單獨埋點,第一步,第二步的耗時 此時出現問題,對某個接口的壓測結果,時快時慢(發現是資源問題)。
- 可能是數據庫耗時太久,有大量慢查詢。
排查方向,在最底層,每一步對數據庫的操作,都埋點排查(優化慢查詢,all查詢,建立索引)
- 網絡延遲(腳本計算錯誤)
發現日志記錄 和壓測結果不符,多方討論后,得出問題在于壓測腳本。
- 可能是加鎖,死鎖等原因
對加鎖埋點記錄,發現部分業務加鎖不正確,如某個死鎖問題,導致用戶超時斷線,則腳本中丟失了一個用戶數,使后期rps越來越低
- 可能是業務邏輯錯誤,混亂,導致問題。
總結
總的來說,遇到很多很多問題,算是各方面的大坑都踩了個遍,大概有以下幾個:
- 針對關鍵業務埋點,優化部分接口(通過壓測結果分析)(如分對推送數據做優先級,分多次下發,和某些業務的異步處理)
- 排查內存泄露(通過pprof抓取)
- 排查鎖問題,對不可重入鎖,重復加鎖(多次調用中間件 重復對不可重入鎖加鎖)
- 排查并發問題(檢查代碼和日志)
- 壓測服務,獨立部署,升級配置(通過Grafana監控)
感悟
總的來說,個人主導的該壓測優化過程,歷經三天四夜,圓滿結束.(壓測穩定,上線不慌)
過程中有疑惑,有壓力,有煩躁也有感悟,不過耐心細致的分析排查,進行了七八個優化,解決了三五個隱患,最終順利的結束壓測,還是很有成就感的.
這是一次很好的解決問題過程,故做此記錄.最終達到1500個用戶量,450rps,其中98%的請求耗時,都在200ms內,90%耗時都在50ms內.且后續進行壓測48小時,仍能保持穩定的rps和合理的資源占用.(撒花 ??ヽ(°▽°)ノ?)
分享
另外分享排查過程中,幾個常用的pprof命令:
可實時抓取目標服務的狀態,并在本地web直接查看火焰圖屬性,非常方便.
- pprof 實時 查看實時內存:
go tool pprof -http=:[本地解析pprof文件的端口(隨便填)] http://[目標服務器IP:端口]/debug/pprof/heap
例子:
go tool pprof -http=:8001 http://127.0.0.1:8087/debug/pprof/heap
- pprof 壓測 實時 查看實時協程:
go tool pprof -http=:[本地端口] http://[目標服務器IP:端口]/debug/pprof/goroutine
- pprof 壓測 實時 查看60s 的cpu占用情況:
go tool pprof -http=:[本地端口] http://[目標服務器IP:端口]/debug/pprof/profile --second=60