C++ Serving 异步模式

May 23, 2022 · View on GitHub

设计方案

一.同步网络线程

Paddle Serving 的网络框架层面是同步处理模式,即 bRPC 网络处理线程从系统内核拿到完整请求数据后( epoll 模式),在同一线程内完成业务处理,C++ Serving 默认使用同步模式。同步模式比较简单直接,适用于模型预测时间短,或单个 Request 请求批量较大的情况。

Server 端线程数 N = 模型预测引擎数 N = 同时处理 Request 请求数 N,超发的 Request 请求需要等待当前线程处理结束后才能得到响应和处理。

二.异步调度线程

为了提高计算芯片吞吐和计算资源利用率,C++ Serving 在调度层实现异步多线程并发合并请求,实现动态批量推理。异步模型主要适用于模型支持批量,单个 Request 请求的无批量或较小,单次预测时间较长的情况。

异步模式下,Server 端 N 个线程只负责接收 Request 请求,实际调用预测引擎是在异步框架的线程池中,异步框架的线程数可以由配置选项来指定。为了方便理解,我们假设每个 Request 请求批量均为1,此时异步框架会尽可能多得从请求池中取 n(n≤M)个 Request 并将其拼装为1个 Request(batch=n),调用1次预测引擎,得到1个 Response(batch = n),再将其对应拆分为 n 个 Response 作为返回结果。

三.动态批量

通常,异步框架合并多个请求的前提是所有请求的 feed var 的维度除 batch 维度外必须是相同的。例如,以 OCR 文字识别案例中检测模型为例,A 请求的 x 变量的 shape 是 [1, 3, 960, 960],B 请求的 x 变量的 shape 是 [2, 3, 960, 960],虽然第一个维度值不相同,但第一个维度属于 batch 维度,因此,请求 A 和 请求 B 可以合并。C 请求的 x 变量的 shape 是 [1, 3, 640, 480],由于除了 batch 维度外还有2个维度值不同,A 和 C 不能直接合并。

从经验来看,当2个请求的同一个变量 shape 维度的数量相等时,通过 padding 补0的方式按最大 shape 值对齐即可。即 C 请求的 shape 补齐到 [1, 3, 960, 960],那么就可以与 A 和 B 请求合并了。Paddle Serving 框架实现了动态 Padding 功能补齐 shape。

当多个将要合并的请求中有一个 shape 值很大时,所有请求的 shape 都要按最大补齐,导致计算量成倍增长。Paddle Serving 设计了一套合并策略,满足任何一个条件均可合并:

  • 条件 1:绝对值差的字节数小于 1024 字节,评估补齐绝对长度
  • 条件 2:相似度的乘积大于 50%,评估相似度,评估补齐绝对值整体数据量比例

场景1:Shape-1 = [batch, 500, 500], Shape-2 = [batch, 400, 400]。此时,绝对值差 = 500*500 - 400*400 = 90000 字节,相对误差= (400/500) * (400/500) = 0.8*0.8 = 0.64,满足条件1,不满足条件2,触发动态 Padding。

场景2:Shape-1 = [batch, 1, 1], Shape-2 = [batch, 2, 2]。此时,绝对值差 = 2*2 - 1*1 = 3字节,相对误差 = (1/2) * (1/2) = 0.5*0.5 = 0.25,满足条件2,不满足条件1,触发动态 Padding。

场景3:Shape-1 = [batch, 3, 320, 320], Shape-2 = [batch, 3, 960, 960]。此时,绝对值差 = 3*960*960 - 3*320*320 = 2457600字节,相对误差 = (3/3) * (320/960) * (320/960) = 0.3*0.3 = 0.09,条件1和条件2均不满足,未触发动态 Padding。

使用案例

一.开启同步模式

启动命令不使用 --runtime_thread_num--batch_infer_size 时,属于同步处理模式,未开启异步模式。--thread 16 表示启动16个同步网络处理线程。

python3 -m paddle_serving_server.serve --model uci_housing_model --thread 16 --port 9292 

二.开启异步模式

启动命令使用 --runtime_thread_num 2--batch_infer_size 32 开启异步模式,Serving 框架会启动2个异步线程,单次合并最大批量为32,自动开启动态 Padding。

python3 -m paddle_serving_server.serve --model uci_housing_model --thread 16 --port 9292 --runtime_thread_num 4 --batch_infer_size 32 --ir_optim --gpu_multi_stream --gpu_ids 0

性能测试

  • GPU:Tesla P4 7611 MiB
  • CUDA:cuda11.2-cudnn8-trt8
  • Python 版本:python3.7
  • 模型:ResNet_v2_50
  • 测试数据:构造全1输入,单client请求100次,shape 范围(1, 224 ± 50, 224 ± 50)

同步模式启动命令:

python3 -m paddle_serving_server.serve --model resnet_v2_50_imagenet_model --port 9393 --thread 8 --ir_optim --gpu_multi_stream --gpu_ids 1 --enable_prometheus --prometheus_port 1939

异步模式启动命令:

python3 -m paddle_serving_server.serve --model resnet_v2_50_imagenet_model --port 9393 --thread 64 --runtime_thread_num 8 --ir_optim --gpu_multi_stream --gpu_ids 1 --enable_prometheus --prometheus_port 19393

一.测试结果

使用异步模式,并开启动态批量后,并发测试不同 shape 数据时,吞吐性能大幅提升。

由于动态批量导致响应时长增长,经过测试,大多数场景下吞吐增量高于响应时长增长,尤其在高并发场景(client=70时),在响应时长增长 33% 情况下,吞吐增加 105%。

Client15102030405070
QPS-2.08%-7.23%-1.89%20.55%23.02%23.34%46.41%105.27%
响应时长2.70%7.09%5.24%13.34%10.80%43.60%8.72%33.89%

异步模式可有效提升服务吞吐性能。

二.测试数据

  1. 同步模式
client_numbatch_sizeCPU_util_pre(%)CPU_util(%)GPU_memory(mb)GPU_util(%)qps(samples/s)total countmean(ms)median(ms)80 percent(ms)90 percent(ms)99 percent(ms)total cost(s)each cost(s)infer_count_totalinfer_cost_total(ms)infer_cost_avg(ms)
111.3018.90206671.5622.93810043.59423.51678.11878.323133.5444.42624.35967100.00001666392.7041.1081
512.0028.20366892.5733.630500148.67339.531373.231396.306419.08815.060614.86767600.00001739372.7480145.9601
1011.9029.80420291.9834.3031000291.51276.728613.963632.7361217.86329.800429.15168600.00001974147.7420234.7750
2014.7049.60473692.6334.3592000582.089154.9521239.1151813.3711858.12859.730358.209312100.00002798459.6330235.6248
3015.7065.70473692.6034.1623000878.164231.1212391.6872442.7442499.96389.654687.816817600.00004100408.9560236.6877
4015.4074.40527092.4434.09040001173.373306.2443037.0383070.1983134.894119.4162117.337721600.00005048139.2170236.9326
5011.4064.70527092.3734.03150001469.250384.3273676.8123784.3304366.862149.7041146.925426600.00006236269.4230237.6260
7013.7079.70527091.8933.97670002060.246533.4395429.2555552.7045661.492210.1008206.025033600.00007905005.9940238.3909
  1. 异步模式 - 未开启动态批量
client_numbatch_sizeCPU_util_pre(%)CPU_util(%)GPU_memory(mb)GPU_util(%)qps(samples/s)total countmean(ms)median(ms)80 percent(ms)90 percent(ms)99 percent(ms)total cost(s)each cost(s)infer_count_totalinfer_cost_total(ms)infer_cost_avg(ms)
116.2013.60517071.1122.89410043.67723.99278.28578.788123.5424.42534.36793695.0000745061.912040.6655
516.1032.20730689.5433.532500149.10943.906376.889401.999422.75315.162314.91134184.0000816834.2250146.7736
1014.9043.60730691.5538.1361000262.21675.393575.788632.0161247.77527.101926.22205107.00001026490.3950227.1464
2015.7039.60730691.3658.6012000341.287145.774646.824994.7481132.97938.391534.12917461.00001555234.6260229.9113
3011.3045.40748491.1069.0083000434.728204.347959.1841092.1811661.28946.382243.473210289.00002269499.9730249.4257
4013.1073.00756291.8380.9564000494.091272.889966.0721310.0111851.88752.060949.409512102.00002678878.2010225.8016
5010.8068.00752291.1083.0185000602.276364.0641058.2611473.0511671.02572.986960.228014225.00003256628.2820272.1385
7016.1078.40758492.0265.06970001075.777474.0142411.2962705.8633409.085111.6653107.578117974.00004139377.4050235.4626
  1. 异步模式 - 开启动态批量
client_numbatch_sizeCPU_util_pre(%)CPU_util(%)GPU_memory(mb)GPU_util(%)qps(samples/s)total countmean(ms)median(ms)80 percent(ms)90 percent(ms)99 percent(ms)total cost(s)each cost(s)infer_count_totalinfer_cost_total(ms)infer_cost_avg(ms)
111.2013.30604870.0722.41710044.60624.48678.36578.707139.3494.52014.46081569.0000462418.639041.7646
511.2050.80711687.3731.106500160.74042.506414.903458.841481.11216.352516.07432059.0000539439.3300157.1851
1010.8026.20726488.7437.4171000267.25479.452604.451686.4771345.52827.984826.72582950.0000752428.0570239.0446
2011.5032.80726489.5270.6412000283.117133.441516.066652.0891274.95733.028028.31214805.00001210814.5610260.5873
3010.9059.10734889.5784.8943000353.380217.385613.587757.8291277.28340.709335.33846924.00001817515.1710276.3695
4011.3057.30735689.3099.8534000400.584204.425666.0151031.1861380.65049.480740.05888104.00002200137.0060324.2558
5011.5050.60757889.04121.5455000411.364331.118605.809874.5431285.65048.234341.13699350.00002568777.6400295.8593
7013.8083.20760289.59133.5687000524.073382.653799.4631202.1791576.80957.288552.407710761.00003013600.9670315.2540