一次 rust 性能调优过程
使用rust开发了一款rpc通信组件,当前支持socket, websocket(udp还在协议设计中)通信,默认编码支持binnary和json两种。为最大化提高通信效率,最大化的不使用锁机制,通信的业务都在单个虚拟线程中运行,提高组件整体QPS。
为进行性能测试,选择了redis和axum对rpc进行比较。
测试场景: 分别开启N个客户端,向服务端发送消息,每个客户端发送M个消息后就停止,服务端接受到消息马上返回消息, rpc还测试binnary和json编码,最终记录总耗时,并按照耗时进行倒排序
测试1: N=6, M=10000
| 栏目 | 编码方式 | 耗时(ms) | ops/s | 排名 |
|---|---|---|---|---|
| rpc-websocket-server | binnary | 2531 | 23706 | 3 |
| rpc-websocket-server | json | 2374 | 25273 | 2 |
| rpc-socket-server | binnary | 2552 | 23510 | 4 |
| rpc-socket-server | json | 2577 | 23282 | 5 |
| auxm-server | json | 2135 | 28103 | 1 |
测试结果竟然是websocket的性能比socket性能强点。
测试2: N=50, M=10000
| 栏目 | 编码方式 | 耗时(ms) | ops/s | 排名 |
|---|---|---|---|---|
| rpc-websocket-server | binnary | 14139 | 35363 | 1 |
| rpc-websocket-server | json | 15070 | 33178 | 4 |
| rpc-socket-server | binnary | 16825 | 29717 | 5 |
| rpc-socket-server | json | 14452 | 34597 | 3 |
| auxm-server | json | 14306 | 34950 | 2 |
测试结果竟然rpc websocket server(binnary)最强,rpc socket server (binnary)最弱,太反常了。
测试3: N=200, M=10000
| 栏目 | 编码方式 | 耗时(ms) | ops/s | 排名 |
|---|---|---|---|---|
| rpc-websocket-server | binnary | 62419 | 32041 | 2 |
| rpc-websocket-server | json | 69215 | 28895 | 4 |
| rpc-socket-server | binnary | 67448 | 29652 | 3 |
| rpc-socket-server | json | 53226 | 37575 | 1 |
| auxm-server | json | 72300 | 27662 | 5 |
测试结果rpc-socket-server(json)性能最好。
初步判断是binnary的codec编码导致的性能低下,就分别对binnary-codec和json-codec进行性能测试。测试结果还真是json-codec比binnary-codec编码性能强。binnary编码主要使用的是bincode, json编码主要使用的是serde-json,对bincode和serde-json的性能测试,明显是bincode性能更强。分析其它编码代码,发现是使用ByteMut编码的缘故,改用Vec后,binnary-codec的性能就比json-codec强了。
但是rpc整体性能还是json比binnary强,未改变上面测试结果。
对比rpc-socket和rpc-websocket,那么共用组件router, channel, service都不是影响性能的原因,那么只能是connection组件导致的性能差异。那对比rpc-socket的binnay和json差异,发现是发送数据存在差异。
差异点:
stream.write_u32(bytes.len() as u32).await?; stream.write_all(&bytes[..]).await?;
上需代码还是认为聪明写法,是节省内存的写法。改成
let result = bytes_wrap(bytes); stream.write_all(&result[..]).await?;
binnay的性能就比json性能强了。重新测试结果如下:
测试4: N=6, M=10000
| 栏目 | 编码方式 | 耗时(ms) | ops/s | 排名 |
|---|---|---|---|---|
| rpc-websocket-server | binnary | 1920 | 31250 | 2 |
| rpc-websocket-server | json | 2544 | 23584 | 5 |
| rpc-socket-server | binnary | 1793 | 33463 | 1 |
| rpc-socket-server | json | 2297 | 26121 | 4 |
| auxm-server | json | 2081 | 28832 | 3 |
这次测试结果rpc-socket>rpc-websocket, binnary>json。是理想结果。
测试5: N=50, M=10000
| 栏目 | 编码方式 | 耗时(ms) | ops/s | 排名 |
|---|---|---|---|---|
| rpc-websocket-server | binnary | 14005 | 35701 | 3 |
| rpc-websocket-server | json | 15078 | 33160 | 5 |
| rpc-socket-server | binnary | 11960 | 41806 | 1 |
| rpc-socket-server | json | 12767 | 39163 | 2 |
| auxm-server | json | 14425 | 34662 | 4 |
测试结果还是很理想的。
测试6: N=200, M=10000
| 栏目 | 编码方式 | 耗时(ms) | ops/s | 排名 |
|---|---|---|---|---|
| rpc-websocket-server | binnary | 63559 | 31466 | 3 |
| rpc-websocket-server | json | 66922 | 29885 | 4 |
| rpc-socket-server | binnary | 51572 | 38780 | 1 |
| rpc-socket-server | json | 55555 | 36000 | 2 |
| auxm-server | json | 67685 | 29548 | 5 |
最后补上对redis的性能测试场景: N个客户端,每个客户端对独自的Key进行set操作M次。
1,N=6, M=10000. 总耗时: 2123ms。 吞吐量:28261 ops/s
2, N=50, M=10000。总耗时: 17087ms。吞吐量: 29262 ops/s
3, N=200, M=10000。总耗时: 63688ms。 吞吐量: 31403 ops/s
结果总结:
1, 虚拟线程是个好东西,但是用不好,也能导致性能降低,毕竟线程切换还是有成本的,在高并发的情况下,需要评估线程的切换成本。
2,bytes是tokio的重要组件,用不好也能影响性能。
测试代码: https://gitee.com/ldh123/rpc-rs/blob/master/rpc-test/src/main.rs (在 rpc-test 目录下,运行 cargo run --release 即可)
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)