C++ Serving框架性能测试

November 14, 2021 · View on GitHub

本文以文本分类任务为例搭建Serving预测服务,给出Serving框架性能数据:

  1. Serving框架净开销测试

  2. 不同模型下预测服务单线程响应时间、QPS、准确率等指标和单机模式的对比

  3. 不同模型下Serving扩展能力对比

1. Serving单次请求时间分解

下图是一个对serving请求的耗时阶段的不完整分析。图中对brpc的开销,只列出了bthread创建和启动开销。

(右键在新窗口中浏览大图)

试与单机模式对比:

  1. 从原始样例填充PaddleTensor (几us到几十us)

  2. 从PaddleTensor填充LoDTensor (几us到几十us)

  3. inference (几十us到几百ms)

  4. 从LoDTensor填充PaddleTensor (几us到几十us)

  5. 从Paddletensor读取预测结果 (几us到几十us)

与单机模式相比,serving模式增加了:

  1. protobuf数据构造和序列化与反序列化 (几us到几十us)

  2. 网络通信 (单机十几us,远程500us到几十ms)

  3. 和bthread创建于调度等。(十几us)

从client端看(图中total time T2),serving模式增加的时间,与inference时间的比例,对整个client端观察到的系统吞吐关系密切:

  1. 当inference时间达到10+ms到几百ms (例如,文本分类的CNN模型),而serving模式增加的时间只有几ms,则client端观察到的吞吐与单机模式几乎一致

  2. 当inference时间只有几个us到几十个us (例如,文本分类的BOW模型),而serving模式增加了几个ms,则client端观察到的吞吐与单机模式相比,会下降到单机模式的20%甚至更低。

为了验证上述假设,文本分类任务的serving模式测试,需要在几个不同模型上分别进行,分别记录serving模式下,client端吞吐量的变化情况。

2. 测试任务和测试环境

2.1 测试任务

文本分类的两种常见模型:BOW, CNN

Batch Size: 本实验中所有请求的batch size均为50

2.2 测试环境

CPU型号、核数内存
Serving所在机器Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz 40核128G
Client所在机器Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz 40核128G

Serving端与Client端通信时延:0.102 ms

3. 净开销测试

本测试是为了描画引入Serving框架后,在Serving端空转的情况下,每query消耗的时间,也就是框架引入的开销。

所谓空转是指,serving端去除实际执行预测的计算时间,但保留拆包和组包逻辑。

模型净开销 (ms)
BOW1
CNN1

在C++ Serving模式下,框架引入的时间开销较小,约为1ms

4. 预测服务单线程响应时间、QPS、准确率等指标与单机模式的对比

本测试用来确定Serving的准确率、QPS和响应时间等指标与单机模式相比是否无明显异常

模型 Serving(client与serving同机器) 单机
QPS Latency (ms) Accuracy QPS Latency (ms) Accuracy
BOW 265.393 3 0.84348 715.973366 1.396700 0.843480
CNN 23.3002 42 0.8962 25.372693 39.412450 0.896200

准确率:Serving模式下与单机模式下预测准确率一致。

QPS:与模型特点有关:可以看到,在预测时间很短的BOW模型上,Serving框架本身的开销和网络通信固定时间在单次请求中的时间占比占了绝大部分,这导致Serving模式下的QPS与单机模式相比下降明显;而在预测时间较长的CNN模型上,Serving框架开销和网络通信时间在单次请求中的占比较小,Serving模式下QPS与单机模式下相差不多。这也验证了第1节的预期。

5. Serving扩展能力

Serving扩展能力的测试是指,在不同模型上:

  1. 固定serving端brpc使用的系统线程数

  2. 不断增加client端并发请求数

  3. 运行一段时间后,client端记录当前设定下QPS、平均响应时间和各个分位点的响应时间等信息

  4. serving与client在不同机器上,Serving端与Client端通信时延:0.102 ms

5.1 测试结论

  1. 当模型较为复杂,模型本身的预测时间较长时(预测时间>10ms,以上述实验中CNN模型为例),Paddle Serving能够提供较好的线性扩展能力.
  2. 当模型是简单模型,模型本身的预测时间较短时(预测时间<10ms,以上述实验中BOW模型为例),随着serving端线程数的增加,qps的增长趋势较为杂乱,看不出明显的线性趋势。猜测是因为预测时间较短,而线程切换、框架本身的开销等占了大头,导致虽然随着线程数增加,qps也有增长,但当并发数增大时,qps反而出现下降。
  3. Server端线程数N的设置需要结合,最大并发请求量,机器core数量,以及预测时间长短这三个因素来确定。
  4. 使用GPU进行模型测试,当模型预测时间较短时,Server端线程数不宜过多(线程数=1~4倍core数量),否则线程切换带来的开销不可忽视。
  5. 使用GPU进行模型测试,当模型预测时间较长时,Server端线程数应稍大一些(线程数=4~20倍core数量)。由于模型预测对于CPU而言是一个阻塞操作,此时当前线程会在此处阻塞等待(类似于Sleep操作),若所有线程均阻塞在模型预测阶段,将没有可运行BRPC的”协程worker“的空闲线程。
  6. 若机器环境允许,Server端线程数应等于或略小于最大并发量。

5.2 测试数据-BOW模型

Serving 4线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
4561.32535637.12659112362
8807.42849549.90857102431
12894.721670613.412318224161
16993.542805216.105722284775
20834.7251198023.961532406481
24649.3161848136.9625067149455
28709.9751971939.4385376159293
32661.8682417448.34956290294560
36551.2343265465.308183129406508
40525.1553808476.168799143464567

Serving 8线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
4397.693502910.0585111575323
8501.567797515.95151825113327
12598.0271003320.06632433125390
16691.3841157123.14273142105348
20468.0992136342.72725374232444
24424.5532826556.531567102353448
28587.6922382247.64576183287494
32692.9112309146.18336694184389
36809.7532222944.45815976256556
40762.1082624352.48697498290475

Serving 12线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
4442.47845209.040512153146
8497.884803416.06881925130330
12797.13752715.05521622162326
16674.7071185723.71543042229455
20489.9562041040.82094968304437
24452.3352652953.05826685341414
28753.0931859037.18125065184421
32932.4981827836.55784862109337
36932.4981930338.60665470110164
40921.5322170343.40665975125451

Serving 16线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
4559.59735747.14859112456
8896.6644618.922512152342
121014.37591511.830516203463
161046.98764115.283721284864
201188.64841316.827623315571
241013.431184123.683334416386
28933.7691499329.9871415291149
32930.6651719234.3844486097137
36880.1532045140.90235772118142
40939.1442129642.59385975126163

Serving 20线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
4686.81329125.825791854
81016.2639367.8737510132433
121282.8746779.3548312153573
161253.13638412.768617234054
201276.49783415.669622285390
241273.34942418.849726356693
281258.311112622.2535314171133
321027.951556531.1308435481103
36912.3161973039.46125266106131
40808.8652472649.45396479144196

Serving 24线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
4635.72831466.2927102248
81089.0336737.3469112140
121087.55505610.113513174151
161251.17639412.789817243954
201241.31805616.113621295172
241327.29904118.083724335977
281066.021313326.2664374784109
321034.331546930.9384415194115
36896.1912008540.17085568110168
40701.5082851057.02087488142199

Serving 28线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
4592.94433736.7468102156
81050.1438097.6199122241
121220.7549159.8313313162651
161178.38678913.57919244165
201184.97843916.878923305172
241234.95971719.434126345394
281162.311204524.0908334070208
321160.351378927.578439477597
36991.791814936.2987506191110
40952.3362100142.00245869105136

Serving 32线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
4654.87930546.109791839
8959.46341698.3392511132439
121222.9949069.8136713163039
161314.71608512.170416203542
201390.63719114.383719244069
241370.8875417.509624304562
281213.81153423.069631376079
321178.21358027.160138456882
361167.691541530.831242517792
40950.8412103442.0692556596137

Serving 36线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
4611.0632736.5467102363
8948.99242158.4310133887
121081.47554811.097215183137
161319.7606212.124116213564
201246.73802116.043422284147
241210.04991719.835428345470
281013.461381427.6296374783125
321104.441448728.975641497288
361089.321652433.0495455583107
40940.1152127442.54815868101138

Serving 40线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
4610.31432776.5558112057
81065.3440018.003510122329
121177.86563211.2645141833310
161252.74638612.772317224063
201290.16775115.503621274766
241153.071040720.815928366481
281300.391076621.532630376078
321222.41308926.178636457599
361141.551576831.5374435283121
401125.241777435.5489485793190

下图是Paddle Serving在BOW模型上QPS随serving端线程数增加而变化的图表。可以看出当线程数较少时(4线程/8线程/12线程),QPS的变化规律非常杂乱;当线程数较多时,QPS曲线又基本趋于一致,基本无线性增长关系。

(右键在新窗口中浏览大图)

5.3 测试数据-CNN模型

Serving 4线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
481.9437244074755648091
8142.4862807353657186106
12173.73234536667986105126
16174.8944574289101109131151
20172.5857944113129138159187
24178.21667334132147158189283
28171.31581721160180192223291
32178.1789802176195208251288
36173.762103590204227241278309
40177.335112781223246262296315

Serving 8线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
486.2999231754450547292
8143.73278305365718391
12178.47133619657785106144
16180.485443258699108131149
20180.46655412108122131153170
24174.45268787134151162189214
28174.15880387157175186214236
32172.85792562182202214244277
36172.171104547206228241275304
40174.435114656226248262306338

Serving 12线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
485.62742335745505575105
8137.6322906355677388134
12187.7933195061737994123
16211.51237823738794113134
20206.6244839793109118145217
24209.93357161111128137157190
28198.68970462137154162186205
32214.02474758146165176204228
36223.94780376158177189222282
40226.04588478174193204236277

Serving 16线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
482.9119241224552607999
8145.822743151636985114
12193.2873104259717792139
16240.4283327463768299127
20249.45740087779199127168
24263.6734551187102110136186
28272.7295133399115123147189
32269.51559366115132140165192
36267.467315131148157184220
40264.93975489147164173200235

Serving 20线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
485.56152337544495573101
8148.765268885061698497
12196.113059557707588108
16241.0873318363768298115
20291.243433665667899114
24301.51539799769097122194
28314.3034454386101109132173
32327.4864885794109118143196
36320.42256176109125133157190
40325.39961463120137145174216

Serving 24线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
485.65682334945505772110
8154.919258204857668195
12221.9922702851616985100
16272.8892931655687489101
20300.9063323363758195108
24326.73536727698287102114
28339.05741291789299119137
32346.8684612788103110130155
36338.42953187102117124146170
40320.91962321119135144176226

Serving 28线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
487.87732275943485276112
8154.5242588649586682100
12192.7093113559727893112
16253.593154759727995129
20288.36734678657884100122
24307.65339005738492116313
28334.10541903789097119140
32348.25459448699107132164
36355.6615061096110118143166
40350.95756987109124133165221

Serving 32线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
487.4088228814348527086
8150.7332653750606885102
12197.4333039057707590106
16250.9173188360737894121
20286.36934920667884102131
24306.02939212748592110134
28323.902432238193100122143
32341.5594684489102111136161
36341.0775277498113124158193
40357.81455895107122133166196

Serving 36线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
486.90362301444495372112
8158.964251634855637991
12205.0862925655687591168
16238.17333589617379100158
20279.70535752677986106129
24318.29437701718289108129
28336.29641630788997119194
32360.295444088497105130154
36353.085098096113123152179
40362.28655205105122134171247

Serving 40线程

并发数QPS总时间平均响应时间80分位点响应时间90分位点响应时间99分位点响应时间99.9分位点响应时间
487.73472279644485473114
8150.4832658150596785149
12202.0882969056697590102
16250.4853193860747993113
20289.6234528657783102132
24314.40838167728390110125
28321.728435158395104132159
32335.0224775890104114141166
36341.45252716101117129170231
40347.95357479109130143182216

下图是Paddle Serving在CNN模型上QPS随serving端线程数增加而变化的图表。可以看出,随着线程数变大,Serving QPS有较为明显的线性增长关系。可以这样解释此图表:例如,线程数为16时,基本在20个并发时达到最大QPS,此后再增加并发压力QPS基本保持稳定;当线程能够数为24线程时,基本在28并发时达到最大QPS,此后再增大并发压力qps基本保持稳定。

(右键在新窗口中浏览大图)