最近由於項目需要,在研究打壓測試工具,以及當測試連接過多後端伺服器配置問題 測試工具選用locust,locust中文意思為蝗蟲,可以想象,locust就像成片的蝗蟲,撲向我們的服務。 它支持分散式的打壓測試,每個實例可自定義執行任務,執行任務可用python腳本實現,具體如何寫python腳本這裡 ...
最近由於項目需要,在研究打壓測試工具,以及當測試連接過多後端伺服器配置問題
測試工具選用locust,locust中文意思為蝗蟲,可以想象,locust就像成片的蝗蟲,撲向我們的服務。
它支持分散式的打壓測試,每個實例可自定義執行任務,執行任務可用python腳本實現,具體如何寫python腳本這裡就不詳細介紹了,網上能搜到很多相關資料,這次的文章主要著重介紹如何實現我們的需求以及對遇到的問題分析。遇到的問題主要是兩個:如何在每次執行任務都使用新的連接,大量連接時如何處理大量出現的TIME_WAIT連接
首先,我的測試場景是,大量的客戶端會間歇性的請求伺服器,並不會長時間連接,基本可以理解為每次請求都是短連接,每條連接發起一次請求後就會斷開。所以首先需要解決的問題是,如何使每次執行任務都是用新的連接。
locust預設使用的是requests庫,創建的會話預設會使用長連接,會復用連接,一條發起多次請求,這並不符合我的要求,所以在每次請求完數據後,我需要自己關閉連接。
關閉連接的手段有很多:
a、斷開整個會話的連接 self.client.close() b、斷開客戶端連接 r = self.client.request("post", "/api/query", data=json.dumps(payload), verify=False)r.connection.close() c、請求時帶著Connection: close頭部,讓伺服器斷開連接(在HTTP1.1協議中,Connection頭部有兩個值,close和keep-alive,這個頭就相當於客戶端告訴服務端,服務端你執行完成請求之後,是關閉連接還是保持連接,保持連接就意味著在保持連接期間,只能由客戶端主動斷開連接) r = self.client.request("post", "/api/query", headers={'Connection':'close'}, data=json.dumps(payload), verify=False) 不論a、b還是c,都能實現每次請求後連接斷開的目的,但是引發的副作用卻不一樣。 因為tcp連接有一種TIME_WAIT狀態,連接的主動關閉方在發送四次揮手的最後一個ACK後會變為TIME_WAIT狀態,保留此狀態的時間為兩個MSL(linux里一個MSL為30s,是不可配置的) 仔細的同學可能已經發現了這裡的區別,a和b方法是客戶端斷開連接,c是伺服器斷開連接,這也就決定了TIME_WAIT會在哪一端出現(前面已經說過,連接的主動關閉方會變為TIME_WAIT狀態)。 抓包驗證發現: a、b方法的FIN報文都是由客戶端發起的
c方法的FIN報文由伺服器發起
如果由伺服器斷開連接,會導致服務器端產生大量TIME_WAIT狀態的連接,這個問題直接的影響就是伺服器的埠很快會被耗盡,導致客戶端無法與伺服器成功建立新的連接
而如果由客戶端斷開連接,經測試,測試機端很快出現上萬的TIME_WAIT狀態的連接,測試量根本打不上去,大量連接建立失敗
所以我們需要調整系統的配置,來優化tcp連接的處理
如果由客戶端關閉連接,需要修改的配置如下: vi /etc/sysctl.conf net.ipv4.tcp_timestamps=1 開啟後下麵的tw參數才能生效net.ipv4.tcp_tw_reuse=1 開啟重用,允許將TIME_WAIT重用與新的連接
net.ipv4.tcp_fin_timeout = 30 縮短TIME_WAIT_2到TIME_WAIT的超時時間 net.ipv4.tcp_max_tw_buckets = 256000 增大最多允許TIME_WAIT的數量 sysctl -p 使能新的配置 如果必須由伺服器斷開連接,這個問題如何優化?(參考鏈接:https://www.jianshu.com/p/2da62c5e10fa) 1,儘量調大系統TIME_WAIT連接數 net.ipv4.tcp_max_tw_buckets = 256000 最多允許time-wait數量,最大閾值 2,調整TIME_WAIT_2到TIME_WAIT的超時時間,預設是60s,優化到30s:
net.ipv4.tcp_fin_timeout = 30 3,下麵再說一些linux里TIME_WAIT專有的優化參數reuse、recycle,預設都是關閉的,這兩個參數必須在timestamps打開的前提下才能生效使用
註意:對於tw的reuse、recycle其實是違反TCP協議規定的,伺服器資源允許、負載不大的條件下,儘量不要打開(副作用大) net.ipv4.tcp_timestamps = 1 net.ipv4.tcp_tw_reuse = 1 機器作為客戶端時起作用,開啟後time_wait在一秒內回收 net.ipv4.tcp_tw_recycle = 0 (建議不要開啟,現在互聯網NAT結構很多,可能直接無法三次握手) 開啟後在3.5*RTO(RTO時間是根據RTT時間計算而來)內回收TIME_WAIT,並60s內同一源ip主機的socket connect請求中的timestamp必須是遞增的,對於服務端,同一個源ip可能會是NAT後很多機器,這些機器timestamp遞增性無可保證,伺服器會拒絕非遞增請求連接,直接導致不能三次握手。
經過權衡,最終決定,伺服器暫時不開啟副作用較大的tw參數,由客戶端斷開連接,修改客戶機的配置。
修改後測試,16個slave實例,模擬480個用戶壓測查詢介面,客戶端與伺服器均不再出現大量TIME_WAIT連接,RPS輕鬆上3k
伺服器硬體配置較低,2核2G記憶體,不需要打的特別狠,滿足需求即可