下面這些概念對於專業做性能測試的會比較熟悉,但是對於開發人員不一定都那么清楚。
- 並發用戶數: 某一時刻同時請求服務器的用戶總數,通常我們也稱並發數,並發連接數等。
- 吞吐率:對於web服務器來說就是每秒處理的請求數,req/sec.
- 服務器平均請求處理時間:服務內部的處理時間,可以理解為我們平時log里的時間。
- 用戶平均請求延遲時間:用戶發送一個請求到接收到響應的時間間隔。
並發用戶數和吞吐率容易被人混淆,除非服務器剛好1秒內能處理完並發用戶的請求,否則兩者數值上沒有必然聯系。一般的服務器都有並發的限制,比如MongoDB的maxConns,Tomcat的maxThreads。
吞吐率和服務器的請求處理時間則互為倒數,其實都是用來衡量服務器內部質量的,而用戶平均請求延遲時間則是在一定並發下用來衡量對單個用戶的服務質量。
一般的隨着並發越來越大,吞吐率是先升后降,因為平均服務器處理時間是吞吐率的倒數,所以它是先降后升,存在一個平衡點,往往超過這個點,吞吐率明顯下降,服務器平均處理時間也會明顯變大。這個平衡點就是我們做壓力測試要尋找的,叫做服務器的最大吞吐率,有時候我們習慣了干脆直接叫做吞吐率了,這時的並發可以叫做最大並發數或者叫最佳並發數。很多人習慣說:某某服務支持多大多大並發,我理解應該就是指的這個數。
而用戶平均請求延遲時間則會隨着並發數的增加而變大,一般在達到服務器的最大並發數之前增加的會比較緩慢,超過之后會驟增。如果一直只有一個用戶請求,那么用戶平均請求延遲時間自然等於服務器平均請求處理時間(忽略網絡耗時),但隨着並發用戶的增加,無論服務器的並發策略如何,用戶的等待時間都會變長,因為假設理想情況,服務器資源無限,所有的請求都是並行處理也僅僅是“等於”,但現實是上下文切換,請求排隊等等的代價不可忽略,所以具體到某個用戶的等待時間就會變長。而服務器平均請求處理時間,隨着資源的充分利用一開始反而可能會下降。
綜上所述,如果用戶平均請求延遲時間 » 服務器平均處理時間,忽略網絡耗時的話,可以說服務器已經存在瓶頸了,說明實際大並發數已經超過服務器的最大並發處理能力了。
我們的生產環境現在就面臨這樣的問題,每天的峰值期間從前面Nginx看平均的響應時間已經達到了3s,但是Tomcat內部的處理時間其實並不到1s,剩下的時間耗在了哪?線程切換,請求排隊…
那么如何在不加機器的情況下優化這個問題呢?既然瓶頸是服務器並發,那么就得想辦法提高並發能力。具體到Tomcat可能是一些參數調優之內的,比如NIO,APR,但這些都做過了之后還有沒有優化的空間呢。最近我准備驗證下Servlet3.0的異步和Jetty的Continuation,總體的思路就是將容器線程和業務線程分開,減小並發的粒度來提高並發。但具體有沒有效果很難說,只有測了才知道,想要並發越高,邏輯就得拆的越細,代價就越高。
最后,實際情況要復雜的多,考慮網絡因素,用戶實際的平均請求延遲時間會更大,而且通常我們缺少這樣的數據參考,所以現在很多都在做端到端的監控。