施壓端飽和是執行負載工具的機器(施壓端,load generator,Gatling 文件也稱 injector,站內其他頁面也寫作壓測機)自己的資源先用完的狀態:CPU、記憶體、網路頻寬、檔案描述元或來源埠不夠,工具送不出設定的負載,或替量到的延遲加上施壓端自己排隊的時間。這時壓測報告上的吞吐量停滯與延遲上升,跟受測服務到達 Saturation Point 的樣子相同,原因卻在施壓端。

概念位置

負載工具量到的延遲,是施壓端從送出請求到處理完回應的時間,這段時間包含施壓端自己的工作:排程虛擬使用者、建立連線、解析回應、寫結果紀錄。施壓端的 CPU 滿了,回應在施壓端排隊等處理;JVM 寫成的工具(Gatling、JMeter)在施壓端做 GC 暫停時,暫停的時間算進那段時間內每一個請求的延遲。所以報告上的延遲由受測服務與施壓端兩邊合成,判讀之前要分得出是哪一邊的貢獻。分的方法是兩邊同時量資源:受測服務照 USE Method 查每一種資源的使用率、飽和與錯誤,施壓端查同一組資源。

施壓端飽和也會讓 open 與 closed 兩種注入方式(Open and Closed Workload Model)失準:open model 下,施壓端送不出設定的到達率,實際抵達的使用者數低於設定值;closed model 下,施壓端的延遲讓每個虛擬使用者送下一個請求的時間往後延,跟受測服務變慢的效果疊在一起。

可觀察訊號與例子

施壓端飽和的訊號有幾種,各自對應一種資源:施壓端的 CPU 接近滿載;JVM 工具的 GC log 出現頻繁或很長的暫停;工具的錯誤訊息出現 Too many open files(檔案描述元的上限,Linux 上由 ulimit -n 決定)或無法指派位址(Cannot assign requested address,錯誤碼 EADDRNOTAVAIL,來源埠用完,常見於大量短連線而連線停在 TIME_WAIT 的情形);open model 下報告上實際抵達的使用者數低於設定的到達率。同一個時段裡,受測服務的 CPU、連線池與佇列都沒有跟著上升時,瓶頸在施壓端的可能性更高。

最直接的確認是比對兩個延遲:負載工具量到的延遲,與受測服務入口量到的同一批請求的延遲。兩者的差距是施壓端加上網路的時間;差距隨負載變大,多出來的延遲就是施壓端或網路加上去的,受測服務那一端的延遲沒有跟著上升。受測服務入口量不到延遲時,用改變施壓端的方法:把同一份負載分到兩台施壓端執行,吞吐量上升、工具量到的延遲下降,原本的上限就是施壓端的;吞吐量與延遲都不變,上限在受測服務或兩者之間的網路。這個比較的前提是兩台施壓端不共用網路出口與宿主機:兩台走同一個 NAT、或跑在同一台 CI runner 主機上時,來源埠與頻寬仍然共用,吞吐量不變也可能是施壓端的網路。只有一台施壓端、受測服務入口也量不到延遲時,讓同一台施壓端用同樣的速率打一個幾乎不做事的 endpoint(健康檢查、回固定內容的靜態頁面):這個 endpoint 在受測服務上的處理時間接近零,工具量到的延遲幾乎全是施壓端與網路的時間,延遲仍然高,代價就在施壓端或網路。這個做法不依賴受測服務離飽和多遠;它只看得出施壓端有沒有貢獻,量不出受測服務的上限。

設計責任

每一次壓測都收集施壓端的資源指標,跟受測服務的指標放在同一個時間軸上;判讀延遲與吞吐量之前,先確認施壓端在整段測試中沒有飽和。施壓端與受測服務放在不同的機器上,否則兩者爭用同一組資源,量到的上限無法歸給其中一方。單台施壓端送不出需要的負載時,執行壓測的人把負載分到多台施壓端,並在結果裡記下施壓端的台數與規格:下一次用不同的施壓端配置重測時,結果才比得了。