如何提升QPS、RT

對(duì)于QPS,RT這些名詞想必大家都不陌生,但是說(shuō)到如何提升他們卻一籌莫展。今天我們就來(lái)研究一下吧

目錄

名稱(chēng)解釋

QPS與線程數(shù)的關(guān)系

最佳線程數(shù)

案例

優(yōu)化方向

QPS與RT的關(guān)系

總結(jié)

名詞解釋

RT(Response Time): 1個(gè)請(qǐng)求所完成的時(shí)間

QPS(Query Per Second): 1秒鐘內(nèi)所完成的請(qǐng)求數(shù)量

QPS與線程數(shù)的關(guān)系

對(duì)于單線程而言,QPS = 1000ms/RT

比如一個(gè)系統(tǒng)只有一個(gè)線程,響應(yīng)時(shí)間為50ms,那么它的qps就是1000/50=20

如果它有兩個(gè)線程,那么它的qps為:20*2=40

這里假設(shè)不受cpu、io、內(nèi)存等其他影響

理論上服務(wù)器能夠支持的線程數(shù)越多,那么qps就會(huì)越高,qps與線程數(shù)成正比例關(guān)系。

image

當(dāng)然,服務(wù)器的資源是有限的,在實(shí)際壓測(cè)過(guò)程中,開(kāi)始時(shí)QPS將隨著線程數(shù)的增加而增加,當(dāng)線程數(shù)達(dá)到一定數(shù)量,達(dá)到cpu瓶頸時(shí),qps保持不變,隨著繼續(xù)壓測(cè),qps還會(huì)略微下降,并且響應(yīng)時(shí)間變長(zhǎng)。

image

原因其實(shí)很簡(jiǎn)單,在cpu資源充足時(shí),線程有足夠的cpu執(zhí)行時(shí)間用于運(yùn)行程序,當(dāng)線程數(shù)達(dá)到一定數(shù)量,同時(shí)cpu資源耗盡時(shí),線程開(kāi)始爭(zhēng)搶cpu,頻繁發(fā)生線程上下文切換(該過(guò)程十分耗時(shí)),線程之間互相等待,響應(yīng)時(shí)間自然增加。

最佳線程數(shù)

通過(guò)QPS與線程數(shù)的關(guān)系,可以很容易的就能得出一個(gè)概念。

最佳線程數(shù):剛好消耗完服務(wù)器資源的臨界線程數(shù)。

公式:最佳線程數(shù) = ((線程等待時(shí)間 + 線程cpu時(shí)間)/ 線程cpu時(shí)間) * cpu數(shù)量

等價(jià)于: 最佳線程數(shù) = (線程等待時(shí)間/ 線程cpu時(shí)間 + 1) * cpu數(shù)量

網(wǎng)上是第一種,等價(jià)的公式是我換算的,因?yàn)槟芙忉尦鼍唧w的意義

當(dāng)然,如果你知道第一種公式的具體意義,還請(qǐng)告訴我

公式說(shuō)明

假設(shè)在單線程情況下,線程等待時(shí)間為100ms,線程cpu時(shí)間為20ms,在線程等待的100ms,cpu是處于空閑狀態(tài),那么我們便可以把這100ms交給其他的線程使用,一共可以給多少個(gè)線程使用呢,每個(gè)線程需要cpu20ms,那么就是:100/20 = 5, 再加上自己這個(gè)線程就是6,所以在這一個(gè)時(shí)間段內(nèi)cpu最大可以支配的線程數(shù)為6,如果服務(wù)器有2個(gè)cpu,那么就是6*2 = 12。

套用公式:(10/2 + 1)*2 = 12

當(dāng)然,在實(shí)際執(zhí)行中,肯定不是他20ms我20ms這樣的,而是cpu為每個(gè)線程分配時(shí)間片交替執(zhí)行

特性

在達(dá)到最佳線程數(shù)時(shí),線程數(shù)量繼續(xù)增加,但qps不變,而響應(yīng)時(shí)間變長(zhǎng),繼續(xù)增加線程數(shù),qps開(kāi)始下降。

如何得到最佳線程數(shù)

1、通過(guò)壓測(cè)的方式,緩慢遞增線程數(shù),觀察壓測(cè)情況,根據(jù)特性會(huì)很容易獲得最佳線程數(shù)

2、通過(guò)公式直接進(jìn)行計(jì)算,這個(gè)方式有點(diǎn)難,因?yàn)槲覀冸y以知道系統(tǒng)的線程cpu時(shí)間與線程等待時(shí)間

3、根據(jù)第一種方式的改進(jìn),進(jìn)行一次壓測(cè),觀察cpu情況,然后將線程數(shù)*(cpu期望值/當(dāng)前cpu值),就會(huì)得到一個(gè)大概值,然后略作調(diào)整即可得到最佳線程數(shù)。

案例

為了更好的認(rèn)識(shí)以上理論,并探討如何提升QPS,我們通過(guò)springboot構(gòu)建一個(gè)測(cè)試案例

定義一個(gè)用于模擬cpu執(zhí)行的方法

public long runCpu(int count){
  long start = System.currentTimeMillis();
  // 用幾個(gè)參數(shù)讓cpu運(yùn)行
  int a = 0;
  double b = 0;
  long c = 0;
  for (int i = 0; i < count; i++) {
    for (int j = 0; j < 100; j++){
      a++;b++;c++;
      a=a*2;b=b/2;
      a=a/2;b=b*2;
      c=c*2;c=c/2;
      a--;b--;c--;
    }
    a++;b++;c++;
  }
  System.out.println(a);
  // 返回運(yùn)行時(shí)間
  return System.currentTimeMillis() - start;
}

count參數(shù)使得該方法的運(yùn)行時(shí)間存在可變性

定義壓測(cè)接口

/**
  * @param count 循環(huán)次數(shù),用于模擬cpu運(yùn)行時(shí)間
  * @param sleep io時(shí)間 毫秒
  */
@GetMapping("/benchmark")
public String qps(int count, long sleep) throws InterruptedException {
  long start = System.currentTimeMillis();
  // cpu運(yùn)行時(shí)間
  long cpuTime = runCpu(count);
  long ioStart = System.currentTimeMillis();
  // 模擬io阻塞
  Thread.sleep(sleep);
  long ioTime = System.currentTimeMillis() - ioStart;
  long total = System.currentTimeMillis() - start;
  return "total: "+ total + " cpu-time:" + cpuTime + " io-time:" + ioTime;
}

為了方便測(cè)試,我將它做成了鏡像,使用docker運(yùn)行

這是我的docker-compose文件,給了2個(gè)cpu

version: '3.5'
services:
  qps-test:
    image: qps-test:1.0.0
    container_name: qps-test
    ports:
      - 8080:8080
    resources:
      limits:
        cpus: '2.00'

第一次測(cè)試,將count調(diào)為100000(這里相當(dāng)于我機(jī)器的cpu-time為10~20ms),io time為80ms

http://192.168.65.206:8080/qps/benchmark?count=100000&sleep=80

得出結(jié)果如下

RT qps cpu 最佳線程數(shù)
103 125 190% 13

單線程的QPS: 1000/103 = 9.7

可能會(huì)有小伙伴不曉得怎么調(diào)出這個(gè)結(jié)果的,這里我簡(jiǎn)單說(shuō)明下

首先我們需要知道,服務(wù)器的瓶頸在cpu上,因?yàn)槲疫@個(gè)案例不可能存在內(nèi)存瓶頸,所以我們需要將cpu壓測(cè)到190%左后(臨界cpu的瓶頸),如果壓到了200%,說(shuō)明此時(shí)線程數(shù)很可能已經(jīng)超了,cpu資源已耗盡,就需要降低線程數(shù),如果沒(méi)到190%,就繼續(xù)增加壓測(cè)線程,直到恒定在190%左右。

壓測(cè)工具我用的是jmeter

有了這個(gè)基準(zhǔn)數(shù)據(jù),現(xiàn)在就要嘗試進(jìn)行提升qps

優(yōu)化方向

根據(jù)公式:QPS = (1000/RT) * 線程數(shù)

由于cpu資源已經(jīng)將要耗盡,那么我們就只能?chē)L試降低響應(yīng)時(shí)間

而響應(yīng)時(shí)間分為兩個(gè)部分:cpu時(shí)間和線程等待時(shí)間,所以我們從這兩個(gè)方面入手。

降低IO等待時(shí)間

我們嘗試將io實(shí)際從80ms降為40ms

http://192.168.65.206:8080/qps/benchmark?count=100000&sleep=40

進(jìn)行壓測(cè)結(jié)果如下:

RT qps cpu 最佳線程數(shù)
65 123 190% 8

單線程QPS: 1000/65 = 15.4

我們發(fā)現(xiàn)響應(yīng)時(shí)間雖然從原來(lái)的103變?yōu)榱?5,但qps卻幾乎未變,而最佳線程數(shù)從13變?yōu)榱?

得出結(jié)論:降低IO時(shí)間并不能提升QPS,為什么?

我們根據(jù)CPU資源恒定原則:CPU資源 = 線程的cpu時(shí)間 * 線程總數(shù) * 單線程的qps

所以得出式子:基準(zhǔn)數(shù)據(jù)的cpu每秒的處理時(shí)間 = 降低IO等待時(shí)間的cpu每秒的處理時(shí)間

23ms * 13 * 9.7 = 25ms * x * 15.4  解出 x = 7.53

其中25ms為RT(65) - IO(40) 15.4為1000/65

線程數(shù) 單線程QPS RT CPU處理時(shí)間 QPS
13 9.7 103 23ms * 13 * 9.7 125
x ≈ 8 15.4 65 25ms * x * 15.4 123

降低CPU執(zhí)行時(shí)間

我們將cpu運(yùn)行時(shí)間削減一般,count值100000 -> 50000

http://192.168.65.206:8080/qps/benchmark?count=50000&sleep=80

進(jìn)行壓測(cè)結(jié)果如下:

RT qps cpu 最佳線程數(shù)
101 244 190% 25

單線程qps: 1000/101 = 9.9

響應(yīng)時(shí)間幾乎未發(fā)生改變,但QPS翻了一倍,最佳線程數(shù)也翻了一倍

得出結(jié)論:降低cpu時(shí)間能顯著提升QPS

同樣根據(jù)CPU資源恒定原則得到:

23ms * 13 * 9.7 = 21ms * x * 9.9

x ≈ 14

由于未知原因,這里翻車(chē)了,按理說(shuō)cpu時(shí)間應(yīng)當(dāng)為10ms左右,因?yàn)閏ount值減半了。

如果cpu時(shí)間為10ms~15ms,那么x就接近25,符合壓測(cè)情況了。這里猜測(cè)是因?yàn)閕o時(shí)間有誤,導(dǎo)致RT變長(zhǎng)。

小結(jié)

count sleep RT qps cpu 最佳線程數(shù)
100000 80ms 103 125 190% 13
100000 40ms 65 123 190% 8
50000 80ms 101 244 190% 25

QPS與RT的關(guān)系

如果說(shuō)單純的根據(jù)公式:QPS = 1000/RT,QPS與RT的關(guān)系如下

image

但通過(guò)案例我們的得知,在實(shí)際情況下,QPS與RT的關(guān)系并非如此,RT中的存在兩種時(shí)間對(duì)QPS有所影響。

CPU執(zhí)行時(shí)間減少,QPS顯著提升。

IO等待時(shí)間減少,QPS提升不明顯或者無(wú)提升。

總結(jié)

通過(guò)以上內(nèi)容分析,如果想要提升RT

1、減少I(mǎi)O的響應(yīng)時(shí)間

2、減少CPU的執(zhí)行時(shí)間

如果想要提升QPS

1、減少CPU的執(zhí)行時(shí)間

2、增加CPU數(shù)量

提示:如果在壓測(cè)過(guò)程中,cpu還未達(dá)到瓶頸,QPS就已經(jīng)達(dá)到了峰值,那么則說(shuō)明存在其他的瓶頸,如內(nèi)存

參考資料

https://www.docin.com/p-73662763.html?docfrom=rrela

追更,想要了解更多精彩內(nèi)容,歡迎關(guān)注公眾號(hào):程序員阿紫

個(gè)人博客空間:https://zijiancode.cn

如果我的文章對(duì)你有所幫助,還請(qǐng)幫忙點(diǎn)贊、轉(zhuǎn)發(fā)一下,你的支持就是我更新的動(dòng)力,非常感謝!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容