03|性能綜述: 怎麼理解TPS、QPS、RT、吞吐量這些性能指標?

  • 2020 年 2 月 24 日
  • 筆記

性能測試第3篇文章

本文約6000字,約15分鐘

在上一篇文章中,我們講述了性能場景,下面就要說性能需求指標了。

通常我們都從兩個層面定義性能場景的需求指標:業務指標和技術指標。

這兩個層面需要有映射關係,技術指標不能脫離業務指標。一旦脫離,你會發現你能回答「一個系統在多少響應時間之下能支持多少 TPS」這樣的問題,但是回答不了「業務狀態是什麼」的問題。

舉例來說,如果一個系統要支持 1000 萬人在線,可能你能測試出來的結果是系統能支持 1 萬 TPS,可是如果問你,1000 萬人在線會不會有問題?這估計就很難回答了。

我在這裡畫一張示意圖以便你理解業務指標和性能指標之間的關係。

這個示意顯然不夠詳細,但也能說明關係了。所有的技術指標都是在有業務場景的前提下制定的,而技術指標和業務指標之間也要有詳細的換算過程。這樣一來,技術指標就不會是一塊飛地。同時,在回答了技術指標是否滿足的同時,也能回答是否可以滿足業務指標。

有了這樣的關聯關係,下面我們看一下性能測試行業常用的性能指標表示法。

我將現在網上能看到的性能指標做了羅列,其中不包括資源的指標。因為資源類的比較具體,並且理解誤差並不大,但業務類的差別就比較大了。

對這些性能指標都有哪些誤解

我記得我還年輕的時候,還沒有 QPS、RPS、CPS 這樣的概念,只有 TPS。那個時候,天總是那麼藍,時間總是那麼慢,「你鎖了人家就懂了」。

QPS 一開始是用來描述 MySQL 中 SQL 每秒執行數 Query Per Second,所有的 SQL 都被稱為 Query。後來,由於一些文章的轉來轉去,QPS 被慢慢地移到了壓力工具中,用來描述吞吐量,於是這裡就有些誤解,QPS 和 TPS 到底是什麼關係呢?

RPS 指的是每秒請求數。這個概念字面意思倒是容易理解,但是有個容易誤解的地方就是,它指的到底是哪個層面的 Request?如果說 HTTP Request,那麼和 Hits Per Second 又有什麼關係呢?

HPS,這也是個在字面意思上容易理解的概念。只是 Hit 是什麼?有人將它和 HTTP Request 等價,有人將它和用戶點擊次數等價。

CPS,用的人倒是比較少,在性能行業中引起的誤解範圍並不大。同時還有喜歡用 CPM(Calls Per Minute,每分鐘調用數)的。這兩個指標通常用來描述 Service 層的單位時間內的被其他服務調用的次數,這也是為什麼在性能行業中誤解不大的原因,因為性能測試的人看 Service 層東西的次數並不多。

為了區分這些概念,我們先說一下 TPS(Transactions Per Second)。我們都知道 TPS 是性能領域中一個關鍵的性能指標概念,它用來描述每秒事務數。我們也知道 TPS 在不同的行業、不同的業務中定義的粒度都是不同的。所以不管你在哪裡用 TPS,一定要有一個前提,就是所有相關的人都要知道你的 T 是如何定義的。

經常有人問,TPS 應該如何定義?這個實在是沒有具體的「法律規定」,那就意味着,你想怎麼定就怎麼定。

通常情況下,我們會根據場景的目的來定義 TPS 的粒度。如果是接口層性能測試,T 可以直接定義為接口級;如果業務級性能測試,T 可以直接定義為每個業務步驟和完整的業務流。

我們用一個示意圖來說明一下。

如果我們要單獨測試接口 1、2、3,那 T 就是接口級的;如果我們要從用戶的角度來下一個訂單,那 1、2、3 應該在一個 T 中,這就是業務級的了。

當然,這時我們還要分析系統是如何設計的。通常情況下,積分我們都會異步,而庫存不能異步哇。所以這個業務,你可以看成只有 1、2 兩個接口,但是在做這樣的業務級壓力時,3 接口也是必須要監控分析的。

所以,性能中 TPS 中 T 的定義取決於場景的目標和 T 的作用。一般我們都會這樣來定事務。

  • 接口級腳本: ——事務 start(接口 1) 接口 1 腳本 ——事務 end(接口 1) ——事務 start(接口 2) 接口 2 腳本 ——事務 end(接口 2) ——事務 start(接口 3) 接口 3 腳本 ——事務 end(接口 3)
  • 業務級接口層腳本(就是用接口拼接出一個完整的業務流): ——事務 start(業務 A) 接口 1 腳本 – 接口 2(同步調用) 接口 1 腳本 – 接口 3(異步調用) ——事務 end(業務 A)
  • 用戶級腳本 ——事務 start(業務 A) 點擊 0 – 接口 1 腳本 – 接口 2(同步調用) 點擊 0 – 接口 1 腳本 – 接口 3(異步調用) ——事務 end(業務 A)

你要創建什麼級別的事務,完全取決於測試的目的是什麼。

一般情況下,我們會按從上到下的順序一一地來測試,這樣路徑清晰地執行是容易定位問題的。

重新理解那些性能指標概念

搞清楚了 TPS 的 T 是什麼,下面就要說什麼是 TPS 了。字面意思非常容易理解,就是:每秒事務數。

在性能測試過程中,TPS 之所以重要,是因為它可以反應出一個系統的處理能力。我在很多場景中都說過,事務就是統計了一段腳本的執行時間,並沒有什麼特別的含義。而現在又多加了其他的幾個概念。

首先是 QPS,如果它描述的是數據庫中的 Query Per Second,從上面的示意圖中來看,其實描述的是服務後面接的數據庫中 SQL 的每秒執行條數。如果描述的是前端的每秒查詢數,那就不包括插入、更新、刪除操作了。顯然這樣的指標用來描述系統整體的性能是不夠全面的。所以不建議用 QPS 來描述系統整體的性能,以免產生誤解。

RPS(Request per second),每秒請求數。看似簡單的理解,但是對於請求數來說,要看是在哪個層面看到的請求,因為請求這個詞,實在是太泛了。我們把上面的圖做一點點變化來描述一下請求數。

如果一個用戶點擊了一次,發出來 3 個 HTTP Request,調用了 2 次訂單服務,調用了 2 次庫存服務,調用了 1 次積分服務,那麼這個 Request 該如何計算?如果你是算 GDP 的專家,我覺得可能會是:3+2+2+1=8(次)。而在具體的項目中,我們會單獨描述每個服務,以便做性能統計。如果要描述整體,最多算是有 3 個 RPS。如果從 HTTP 協議的角度去理解,那麼 HTTP Request 算是一個比較準確的描述了,但它本身的定義並沒有包含業務。如果賦予它業務的含義,那麼用它來描述性能也是可以的。

HPS(Hits Per Second),每秒點擊數。Hit 一般在性能測試中,都用來描述 HTTP Request。但是,也有一些人用它描述真正的客戶在界面上的點擊次數。關於這一點,就只有在具體的項目中才能規定得具體一些。當它描述 HTTP Request 時,如果 RPS 也在描述 HTTP Request,那這兩個概念就完全一樣了。

CPS/CPM:Calls Per Second/ Calls Per Minutes,每秒 / 每分鐘調用次數。這個描述在接口級是經常用到的,比如說上面的訂單服務。顯然一次客戶界面上的點擊調用兩次。這個比較容易理解。但是,在操作系統級,我們也經常會聽到系統調用用 call 來形容,比如說用 strace 時,你就會看見 Calls 這樣的列名。

這些概念本身並沒有問題,但是當上面的概念都用來描述一個系統的性能能力的時候,就混亂了。對於這種情況,我覺得有幾種處理方式:

1.用一個概念統一起來。我覺得直接用 TPS 就行了,其他的都在各層面加上限制條件來描述。比如說,接口調用 1000 Calls/s,這樣不會引起混淆。

2.在團隊中定義清楚術語的使用層級。

3.如果沒有定義使用層級,那隻能在說某個概念的時候,加上相應的背景條件。

所以,當你和同事在溝通性能指標用哪些概念時,應該描述得更具體一些。在一個團隊中,應該先有這些術語統一的定義,再來說性能指標是否滿足。

響應時間 RT

在性能中,還有一個重要的概念就是響應時間(Response Time)。這個比較容易理解。我們接着用這張示意圖說明:

RT = T2-T1。計算方式非常直接簡單。但是,我們要知道,這個時間包括了後面一連串的鏈路。

響應時間的概念簡單至極,但是,響應時間的定位就複雜了。

性能測試工具都會記錄響應時間,但是,都不會給出後端鏈路到底哪裡慢。經常有人問問題就直接說,我的響應時間很慢。問題在哪呢?在這種情況下,只能回答:不知道。

因為我們要先畫架構圖,看請求鏈路,再一層層找下去。比如說這樣:

在所有服務的進出口上都做記錄,然後計算結果就行了。在做網關、總線這樣的系統時,基本上都會考慮這個功能。

而現在,隨着技術的發展,鏈路監控工具和一些 Metrics 的使用,讓這個需求變得簡單了不少。比如說這樣的展示:

它很直觀地顯示了,在一個請求鏈路上,每個節點消耗的時間和請求的持續時間。

我順便在這裡說一下調優在當前性能項目中的狀態。

對於響應時間來說,時間的拆分定位是性能瓶頸定位分析中非常重要的一節。但是請注意,這個環節並不是性能測試工程師的最後環節。

在工作中,我經常看到有很多性能測試工程師連時間拆分都不做,只報一個壓力工具中看到的響應時間,就給一個通過不通過的結論,絲毫沒有定位。

另外,有一些性能測試工程師,倒是用各種手段分析了時間的消耗點,但是也覺得自己的工作就此結束了,而不做根本原因的分析或協調其他團隊來分析。

當然在不同的企業里,做分析的角色和要求各不相同,所以也要根據實際的企業現狀來說。

在我的觀點中,性能只測不調,那就是性能驗證的工作,稱不上是完整的性能項目。第三方性能測試的機構可以這樣做,但是在一個企業內部這樣做的話,性能團隊的價值肯定就大打折扣了。

但是現在有很多人都不把性能調優做為性能團隊的工作,主要原因有幾點:

1.性能測試團隊的人能力有限做不到;

2.性能調優代價高,耗時長,不值得做。

在我帶的性能項目中,基本上調優的工作都是我的團隊主導的。性能團隊當然不可能完全沒有技術弱點,所以在很多時候都是協調其他團隊的人一起來分析瓶頸點。那為什麼是我的團隊來主導這個分析的過程呢?

因為每個技術人員對性能瓶頸的定義並不相同,如果不細化到具體的計數器的值是多少才有問題,有誤解的可能性就很大。

曾經我在某零售業大廠做性能諮詢的時候,一房間的技術人員,開發、運維、DBA 都有,結果性能瓶頸出現了,所有人都說自己的部分是沒問題的。於是我一個個問他們是如何判斷的,判斷的是哪個計數器,值又是多少。結果發現很多人對瓶頸的判斷都和我想像的不一樣。

舉例來說,DB 的 CPU 使用率達到 90% 以上,DBA 會覺得沒有問題,因為都是業務的 SQL,並不是 DB 本身有問題。開發覺得 SQL 執行時間慢是因為 DB 有問題,而不是自己寫的有問題,因為業務邏輯並沒有錯,有問題的點應該是 DB 上索引不合理、配置不合理。

你看,同樣的問題,每個人的看法都有區別。當然也不能排除有些人就是想推諉責任。

這時怎麼辦呢?如果你可以把執行計劃拿出來,告訴大家,這裡應該創建索引,而那裡應該修改業務條件,這時就具體了。

壓力工具中的線程數和用戶數與 TPS

總是有很多人在並發線程數和 TPS 之間遊盪,搞不清兩者的關係與區別。這兩個概念混淆的點就是,好像線程是真實的用戶一樣,那並發的線程是多少就描述出了多少真實的用戶。

但是做性能的都會知道,並發線程數在沒有模擬真實用戶操作的情況下,和真實的用戶操作差別非常遠。

在 LoadRunner 還比較紅火的時候,Mercury 提出一個 BTO 的概念,就是業務科技優化。在 LoadRunner 中也提出」思考時間「的概念,其實在其他的性能工具中是沒有「思考時間」這個詞的。這個詞的提出就是為了性能工具模擬真實用戶。

但是隨着性能測試的地位不斷下降,以及一些概念和名詞不斷地被以訛傳訛,導致現在很多人都沒有明白壓力工具中的線程數和用戶以及 TPS 之間是怎樣的關係。同樣,我們先畫一個示意圖來說明一下。

這裡先說明一個前提,上面的一個框中有四個箭頭,每個都代表着相同的事務。

在說這個圖之前,我們要先說明「並發」這個概念是靠什麼數據來承載的。

在上面的內容中,我們說了好多的指標,但並發是需要具體的指標來承載的。你可以說,我的並發是 1000TPS,或者 1000RPS,或者 1000HPS,這都隨便你去定義。但是在一個具體的項目中,當你說到並發 1000 這樣沒有單位的詞時,一定要讓大家都能理解這是什麼。

在上面這張示意圖中,其實壓力工具是 4 個並發線程,由於每個線程都可以在一秒內完成 4 個事務,所以總的 TPS 是 16。這非常容易理解吧。而在大部分非技術人的腦子裡,這樣的場景就是並發數是 4,而不是 16。

要想解釋清楚這個非常困難,我的做法就是,直接告訴別人並發是 16 就好了,不用關心 4 個線程這件事。這在我所有項目中幾乎都是一樣的,一直也沒有什麼誤解。

那麼用戶數怎麼來定義呢?涉及到用戶就會比較麻煩一點。因為用戶有了業務含義,所以有些人認為一個系統如果有 1 萬個用戶在線,那就應該測試 1 萬的並發線程,這種邏輯實在是不技術。通常,我們會對在線的用戶做並發度的分析,在很多業務中,並發度都會低於 5%,甚至低於 1%。

拿 5% 來計算,就是 10000 用戶 x5%=500(TPS),注意哦,這裡是 TPS,而不是並發線程數。如果這時響應時間是 100ms,那顯然並發線程數是 500TPS/(1000ms/100ms)=50(並發線程)。

通過這樣簡單的計算邏輯,我們就可以看出來用戶數、線程數和 TPS 之間的關係了。

是!響應時間肯定不會一直都是 100ms 的嘛。所以通常情況下,上面的這個比例都不會固定,而是隨着並發線程數的增加,會出現趨勢上的關係。

所以,在性能分析中,我一直在強調着一個詞:趨勢

業務模型的 28 原則是個什麼鬼?

我看到有些文章中寫性能測試要按 28 原則來計算並發用戶數。大概的意思就是,如果一天有 1000 萬的用戶在使用,系統如果開 10 個小時的話,在計算並發用戶數的時候,就用 2 小時來計算,即 1000 萬用戶在 2 小時內完成業務。

我要說的是,這個邏輯在一個特定的業務系統中是沒有任何價值的。因為每個系統的並發度都由業務來確定,而不是靠這樣的所謂的定律來支配着業務。

如果我們做了大量的樣本數據分析,最後確實得出了 28 的比例,我覺得那也是可以的。但是如果什麼數據都沒有分析,直接使用 28 比例來做評估和計算,那就跟耍流氓沒有區別。

業務模型應該如何得到呢?這裡有兩種方式是比較合理的:

1.根據生產環境的統計信息做業務比例的統計,然後設定到壓力工具中。有很多不能在線上直接做壓力測試的系統,都通過這種方式獲取業務模型。

2.直接在生產環境中做流量複製的方式或壓力工具直接對生產環境發起壓力的方式做壓力測試。這種方式被很多人稱為全鏈路壓測。其實在生產中做壓力測試的方式,最重要的工作不是技術,而是組織協調能力。相信參與過的人都能體會這句話的重量。

響應時間的 258 原則合理嗎?

對於響應時間,有很多人還在說著 258 或 2510 響應時間是業內的通用標準。然後我問他們這個標準的出處在哪裡?誰寫的?背景是什麼?幾乎沒有人知道。真是不能想像,一個誰都不知道出處的原則居然會有那麼大的傳播範圍,就像謠言一樣,出來之後,再也找不到源頭。

其實這是在 80 年代的時候,英國一家 IT 媒體對音樂緩衝服務做的一次調查。在那個年代,得到的結果是,2 秒客戶滿意度不錯;5 秒滿意度就下降了,但還有利潤;8 秒時,就沒有利潤了。於是他們就把這個統計數據公布了出來,這樣就出現了 258 principle,翻譯成中文之後,它就像一個萬年不變的定理,深深影響着很多人。

距離這個統計結果的出現,已經過去快 40 年了,IT 發展的都能上天了,這個時間現在已經完全不適用了。所以,以後出去別再提 258/2510 響應時間原則這樣的話了,太不專業。

那麼響應時間如何設計比較合理呢?這裡有兩種思路推薦給你。

1.同行業的對比數據。

2.找到使用系統的樣本用戶(越多越好),對他們做統計,將結果拿出來,就是最有效的響應時間的制定標準。

性能指標的計算方式

我們在網上經常可以看到有人引用這幾個公式。

公式(1):

並發用戶數計算的通用公式:

其中 C 是平均的並發用戶數;n 是 login session 的數量;L 是 login session 的平均長度;T 指考察的時間段長度。

公式(2):

並發用戶數峰值:

C』指並發用戶數的峰值,C 就是公式(1)中得到的平均的並發用戶數。該公式是假設用戶的 login session 產生符合泊松分佈而估算得到的。

仔細搜索之後發現會發現這兩個公式的出處是 2004 年一個叫 Eric Man Wong 的人寫的一篇名叫《Method for Estimating the Number of Concurrent Users》的文章。中英文我都反覆看到很多篇。同時也會網上看到有些文章中把這個文章描述成「業界公認」的計算方法。

在原文中,有幾個地方的問題。

1.C 並不是並發用戶,而是在線用戶。

2.這兩個公式做了很多的假設條件,比如說符合泊松分佈什麼的。為什麼說這個假設有問題?我們都知道泊松分佈是一個鍾型分佈,它分析的是一個系統在全周期中的整體狀態。

3.如果要讓它在實際的項目中得到實用,還需要有大量的統計數據做樣本,代入計算公式才能驗證它的可信度。

4.峰值的計算,我就不說了,我覺得如果你是做性能的,應該一看就知道這個比例不符合大部分真實系統的邏輯。

5.有些人把這兩個公式和 Little 定律做比較。我要說 Little 定律是最基礎的排隊論定律,並且這個定律只說明了:系統中物體的平均數量等於物體到達系統的平均速率和物體在系統中停留的平均時間的乘積。我覺得這句話,就跟秦腔中的」出門來只覺得脊背朝後「是一樣一樣的。

有人說應該如何來做系統容量的預估呢。我們現在很多系統的預估都是在一定的假設條件之下的,之所以是預估,說明系統還不在,或者還沒達到那樣的量。在這種情況下,我們可以根據現有的數據,做統計分析、做排隊論模型,進而推導以後的系統容量。

但是我們所有做性能的人都應該知道,系統的容量是演進來的,而不是光憑預估就可以得出準確數值的。

總結

今天的這一篇和前兩篇文章是一個體系,我利用這三篇文章對當前的性能測試市場上的一些關鍵概念進行一些拆解。性能測試策略、性能測試場景、性能測試指標,這些關鍵的概念在性能測試中深深地影響着很多人。我們簡化它的邏輯,只需要記住幾個關鍵字就可以,其他的都不必使用。

1.性能測試概念中:性能指標、性能模型、性能場景、性能監控、性能實施、性能報告。

2.性能場景中:基準場景、容量場景、穩定性場景、異常場景。

3.性能指標中:TPS、RT。(記住 T 的定義是根據不同的目標來的)

有了這些之後,一個清晰的性能框架就已經出現了。

思考題

你能思考一下,為什麼 258 響應時間不合理嗎?像「業務模型用 28 原則」這些看似常識性的知識點,錯在哪裡呢?

歡迎你留言寫下你的思考,我會和你一起交流,也歡迎把這篇文章分享給你的朋友或者同事,一起交流一下。