跟我一起認識Little’s Law

1.前言

開發的同學或多或少都會跟“性能”這個玩意打交道,本文將要介紹的Little’s Law跟衡量性能的常見指標關係密切,所以在引出今天的主角Little’s Law之前,有必要先統一一下我們描述“性能”的“基本語言”,畢竟語言不通是沒法交流的不是。另外,以下敘述都是我的個人理解,不當之處請指正。

2.“性能”的“基本語言”

不同的服務設備對性能的定義也不同,例如CPU主要看主頻,磁盤主要看IOPS。本文主要針對後端的軟件服務性能(比如api服務、數據庫服務等)展開討論。限定好範圍後就應該給出一個性能的定義了:性能就是服務的處理請求的能力

衡量性能的指標常見的有三個:併發用戶數、吞吐量、響應時間。

2.1併發用戶數

指真正對服務發送請求的用戶數量,需要注意和在線用戶數的區別;

比如,某一時刻,在線用戶數爲1000,其中只有100個用戶的操作觸發了與遠端服務的交互,那麼這時對遠端服務來說,併發用戶數是100,而不是1000。

2.2吞吐量

單位時間內處理的請求數。

2.3響應時間

對應的英文是response time,也有的地方用 latency表示,即延遲。需要統計一個時間段內的響應時間,求出特徵值來表示響應時間。

常見的特徵值包括平均值、最大值、最小值、分位值。

3.主角Little’s Law登場

3.1 Little’s Law的定義

穩定的系統中同時被服務的用戶數量等於用戶到達系統的速度乘以每個用戶在系統中駐留的時間,適用於所有需要排隊的場景。

對應公式表示爲:

N = X * R,其中
N 表示系統中同時活動的用戶,
X 表示用戶相繼到達系統的速率,在穩定(這個詞非常重要!!!)狀態(用戶到達系統的速度等於用戶離開系統的速度)時即爲系統吞吐量,
R 表示每個用戶在系統中平均的駐留時間。

比如說,你正在排隊進入一個體檢中心,你可以通過估計人們進入的速率來知道自己還要等待多長時間。

體檢中心能容納約600人,每個人完成體檢的時間是2個小時,
即R=2小時,N=600人,根據公式計算:
X=N/R=600人/2小時=300人/小時
所以以每小時300人的速度進入。
如果現在你的前面還有300個人,那麼大約還要等上一個小時纔會進入體檢中心。

3.2 Little’s Law與性能指標的關係

前一部分說的三個指標的關係可以用Little’s Law來表示,因爲對用戶請求不斷髮送到服務端進行處理的情況來說,就是一種排隊的場景,把Little’s Law具體到這種場景那麼對應的公式爲:

併發數=吞吐量*響應時間

3.3 通過實例感受Little’s Law的存在

下面主要從接口服務和mysql服務兩個實例來觀察Little’s Law的存在。

3.3.1 接口服務的實例

3.3.1.1 準備過程介紹
  1. 基於springboot暴露一個接口

接口本身會根據參數值休眠一段時間,這樣客戶端的壓測工具就可以控制接口的響應時間了。

@RestController
public class ApiLatency {

    @RequestMapping("/test/latency/{ms}")
    public String latency(@PathVariable long ms) {

        try {
            Thread.sleep(ms);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return "Hello World!";
    }
}
  1. 通過jmeter設置不同的併發數對上面的接口進行壓測
3.3.1.2 結果展示與分析

初始階段響應時間基本穩定,吞吐量隨着併發數的增加而增加;

隨着併發數增加,系統到達“拐點”,吞吐量開始出現下降的趨勢,同時響應時間也開始增大;繼續增加併發數,系統負載超負荷,從而進入過飽和區,此時響應時間急劇增大,吞吐量急劇下降。在“拐點”之前和剛進入拐點這段區域,此時可以認爲系統爲“穩定”的,此時併發數、吞吐量、平均響應時間是符合Little’s Law公式的。

3.3.2 mysql服務的實例

3.3.2.1 準備過程介紹
  1. 準備一個騰訊雲mysql服務(5.6版本,配置爲2核4G)和一臺雲服務器(騰訊雲內網測試)
  2. 用sysbench(0.5版本)對mysql服務進行測試
## 數據預置
sysbench --mysql-host=192.168.0.10 --mysql-port=3306 --mysql-user=root --mysql-password=test --mysql-db=loadtest --mysql-table-engine=innodb --test=/usr/local/share/sysbench/tests/include/oltp_legacy/oltp.lua --oltp_tables_count=8 --oltp-table-size=4000000  --rand-init=on prepare

## 執行shell腳本進行測試
for i in 5 7 8 10 12 25 50 128 200 400 700 1000
do
sysbench --mysql-host=192.168.0.10 --mysql-port=3306 --mysql-user=root --mysql-password=test --mysql-db=loadtest  --test=/usr/local/share/sysbench/tests/include/oltp_legacy/oltp.lua --oltp_tables_count=8 --oltp-table-size=4000000 --num-threads=${i} --oltp-read-only=off --rand-type=special --max-time=180 --max-requests=0 --percentile=99 --oltp-point-selects=4 --report-interval=3 --forced-shutdown=1 run | tee -a sysbench.${i}.oltp.txt
done

## 清理數據
sysbench --mysql-host=192.168.0.10 --mysql-port=3306 --mysql-user=root --mysql-password=test --mysql-db=loadtest --mysql-table-engine=innodb --test=/usr/local/share/sysbench/tests/include/oltp_legacy/oltp.lua --oltp_tables_count=8 --oltp-table-size=4000000  --rand-init=on cleanup

## 腳本中參數的含義
--oltp_tables_count=8,表示本次用於測試的表數量爲8張。
--oltp-table-size=4000000,表示本次測試使用的錶行數均爲400萬行。
--num-threads=n,表示本次測試的客戶端連接併發數爲n。
--oltp-read-only=off ,off 表示測試關閉只讀測試模型,採用讀寫混合模型。
--rand-type=special,表示隨機模型爲特定的。
--max-time=180,表示本次測試的執行時間180秒。
--max-requests=0,0 表示不限制總請求數,而是按 max-time 來測試。
--percentile=99,表示設定採樣比例,默認是95%,即丟棄1%的長請求,在剩餘的99%裏取最大值。
--oltp-point-selects=4,表示 oltp 腳本中 sql 測試命令,select 操作次數爲4,默認值爲1。
3.3.2.2 結果展示與分析

初始階段響應時間基本穩定,吞吐量隨着併發數的增加而增加;

隨着併發數增加,系統到達“拐點”,吞吐量開始出現下降的趨勢,同時響應時間也開始增大;繼續增加併發數,系統負載超負荷,從而進入過飽和區,此時響應時間急劇增大,吞吐量急劇下降。在“拐點”之前和剛進入拐點這段區域,此時可以認爲系統爲“穩定”的,此時併發數、吞吐量、平均響應時間是符合Little’s Law公式的。

4.總結

4.1 Little’s Law公式系統“穩定”時成立

基於前述的兩個實測的例子,對於併發數、吞吐量、響應時間三者的關係,我們可以用上圖表示。

  • 剛開始爲“線性增長區”,此時響應時間基本穩定,吞吐量隨着併發用戶數的增加而增加;
  • 當系統的資源利用率飽和時,系統到達“拐點”,隨着併發用戶數增加,吞吐量開始出現下降的趨勢,同時響應時間也開始增大;
  • 繼續增加併發用戶數,系統負載超負荷,從而進入過飽和區,此時響應時間急劇增大,吞吐量急劇下降。

在“拐點”之前和剛進入拐點這段區域,此時可以認爲系統爲“穩定”的,此時併發數、吞吐量、平均響應時間是符合Little’s Law公式的。

4.2 併發數並不是實際用戶數

比如你這樣設置jmeter的線程數爲80,測出的結果並不是說你的服務在80個用戶使用情況下的性能表現,實際場景中可能1000個真實用戶產生的壓力也沒有這裏的80個線程(或者叫虛擬用戶數)產生的壓力大。我傾向於把併發數理解爲一種壓力的度量,80的併發對服務的壓力肯定是大於60的併發對服務的壓力的。

4.3 低延遲(響應時間)不一定高吞吐,高延遲(響應時間)也不一定低吞吐

  • 假如一個程序只有1個線程,這個線程每秒可以處理10次事件,那麼我們說這個程序處理單次事件的延遲爲100ms,吞吐爲10次/秒。
  • 假如一個程序有4個線程,每個線程每秒可以處理5次事件,那麼我們說這個程序處理單次事件的延遲爲200ms,吞吐爲20次/秒。
  • 假如一個程序有1個線程,每個線程每秒可以處理20次事件,那麼我們說這個程序處理單次事件的延遲爲50ms,吞吐爲20次/秒。

由Little’s Law我們知道,併發數=吞吐量*響應時間,所以延遲和吞吐的關係是受併發數影響的,拋開併發數去找另外兩者的關係是沒有規律的。

4.4 響應時間要和吞吐量掛鉤

性能如果只看吞吐量,不看響應時間是沒有意義的。從前面的分析我們知道,隨着併發數的逐漸增加,吞吐量有一個先上升再下降的過程,也就是存在同一個吞吐量的值,在不同併發下,會對應不同的響應時間。比如某接口吞吐量爲10000TPS,響應時間達到5秒,那這個10000TPS也沒什麼意義了。

4.5 響應時間、吞吐量和成功率要掛鉤

比如在接口測試中,當併發數達到4000時,錯誤率達到了40%,那麼此時的1270.8TPS就沒什麼意義了。

4.6 又多又快又好

我理解的服務的性能就是又多又快又好的處理請求,“多”就是吞吐量大,“快”就是響應時間短,“好”就是錯誤率儘量低。

4.7 last but not least

在Little’s Law中我們一直用的響應時間是“平均響應時間”,而實際工作中我們通常用響應時間的“分位值”來作爲響應時間的統計值來衡量性能的,平均值只是作爲一個輔助參考。原因你應該懂得,比如“平均工資”通常沒多大參考價值,有可能很多人是被平均的。

5.擴展

Eric Man Wong 於2004年發表的《Method for Estimating the Number of Concurrent Users》論文中介紹了一種對系統併發用戶數估算的公式:

這個公式和Little’s Law是等價的,具體論述過程參考Eric’s併發用戶數估算與Little定律的等價性

6.參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章