轉自: https://mp.weixin.qq.com/s?__biz=MzIxMjAzMDA1MQ==&mid=2648946009&idx=1&sn=3a0be2fe4f098de819f7dc05b79c593f&chksm=8f5b5255b82cdb43fa8714aed8c351306596492396467bf85d8e14ee476e944e5e58bb0ba724#rdgit
作壓力測試的時候但願能夠在服務器上採樣,能得到當前服務器的TCP鏈接數、鏈接耗費時間的最大值、最小值、均值。github
TCP鏈接採樣最直接的方式是經過netstat統計ESTABLISHED
狀態的TCP鏈接數。通常壓力測試工具會提供一份報告說明發送請求的最大值、最小值、均值。數組
netstat原理是讀取/proc/net/tcp給出當前服務器的TCP狀態,當「列表」很長的時候它就要花費更多時間完成解析。採樣到的數據不及時,並且nestat會消耗很是大的CPU,影響測試結果;服務器
壓力測試工具報告的請求耗費時間的最大值、最小值、均值包含了網絡延時。壓力測試工具會同時開啓N個併發訪問服務器,對於網絡來講是有大量的數據包同時產生,極可能受限於測試機或者服務器的帶寬,根本沒有送到服務器或者是測試機來不及處理產生了延時;網絡
最好的辦法是經過內核Hook攔截某些關鍵的TCP函數,好比能找到相似tcp_connect、tcp_close的函數。遺憾的是TCP創建鏈接比較容易找到(無非是accept、tcp_v4_connect之類的),可是關閉部分卻沒有相應的函數。這個問題折騰了我很多時間,最後我借鑑了nestat的思路——經過TCP的狀態判斷。併發
至於Hook內核基本上沒什麼難度,祭出大殺器Systemtap就好了。tcp
Systemtap是世界上最牛B的Linux內核調試工具(沒有之一),若是你以前據說過DTrace那麼能夠把它理解爲DTrace for Linux。使用它經過簡單的幾行代碼咱們就能夠Hook到內核中的任何函數,不但能夠「截獲」參數甚至能夠修改參數。函數
我定義了一個全局數組connection
,當TCP狀態是ESTABLISHED
時我會把時間戳放到以客戶端IP地址+端口爲Key的關聯數組中,當TCP狀態是CLOSE、CLOSE_WAIT時根據IP地址和端口取出時間戳,計算出耗費的毫秒數放入累加變量spend_time中。爲了統計當前併發數,程序中每隔1秒鐘,修改report關聯數組。工具
最後在程序結束的時候輸出全部請求耗費時間的最大值、最小值和均值。學習
經過ab簡單的模擬一下效果,設置併發度300,總的請求數量是10000。
結果顯示ab記錄發送了10000次而實際上服務器多收到146次,這部分請求應該是ab認爲失敗其實已經成功的。服務器的峯值是179,遠遠沒有達到300的併發度。
附上systemtap腳本地址
https://gist.github.com/fireflyc/cf82f27ebbfe1ff61c4f789b8b1b0d25
這篇文章的目的實際上是想讓你們學習用systemtap。網上關於它的教程不少,因此再寫一篇「教程」也不可能好到哪裏去。因此介紹一個以前寫過的一個腳本,但願可以拋磚引玉。
歡迎關注公衆帳號瞭解更多信息「寫程序的康德——思考、批判、理性」