当前位置: 首页 > news >正文

2508C++,支持rdma通信的高性能rpc库

原文

[重磅]支持rdma通信的高性能rpc库–yalantinglibs.coro_rpc

yalantinglibscoro_rpc是基于C++20协程高性能rpc库,提供了简洁易用的接口,让用户几行代码就可实现rpc通信,现在coro_rpc除了支持tcp通信之外还支持了rdma通信(ibverbs).
通过简单示例来感受一下rdma通信的coro_rpc.

示例

启动rpcserver

std::string_view echo(std::string str) { return str; }
coro_rpc_server server(/*thread_number*/ std::thread::hardware_concurrency(), /*端口*/ 9000);
server.register_handler<echo>();
server.init_ibv();//初化rdma资源
server.start();

客户发送rpc请求

Lazy<void> async_request() {coro_rpc_client client{};client.init_ibv();//初化rdma资源co_await client.connect("127.0.0.1:9000");auto result = co_await client.call<echo>("hello rdma");assert(result.value() == "hello rdma");
}
int main() {syncAwait(async_request());
}

几行代码就可完成基于rdma通信的rpcserver客户了.如果用户需要设置更多rdma相关的参数,则可在调用init_ibv时传入配置对象,在该对象中设置ibverbs相关的各种参数.详见文档.

如果要允许tcp通信该怎么做呢?不调用init_ibv()即可,默认就是tcp通信,调用了init_ibv()之后才是rdma通信.

benchmark

180Gbrdma(RoCEV2)带宽环境,两台主机之间对coro_rpc做了一些性能测试,在高并发小包场景下qps可到150w;
发送稍大的数据包时(256K以上)不到10个并发就可轻松打满带宽.

请求数据大小并发数吞吐(Gb/s)P90(us)P99(us)qps
128B10.04242643394
-40.152944149130
-160.404861393404
-640.81100134841342
-2561.472102561533744
4K11.21353937017
-44.503748137317
-1611.646274355264
-6424.47112152745242
-25642.362443121318979
32K18.41394132084
-429.914255114081
-1683.735893319392
-64148.66146186565878
-256182.74568744697849
256K128.59819013634
-4100.079611347718
-16182.5821024287063
-64181.7077686487030
-256180.983072339288359
1M155.081581726566
-4161.9023625419299
-16183.4183288821864
-64184.292976310421969
-256184.90116481177622041
8M178.6484014881171
-4180.88153618402695
-16185.01588860102756
-64185.0123296235522756
-256183.4793184942082733

具体benchmark的代码在此.

RDMA优化性能

RDMA内存池

rdma请求,需要预先注册内存收发数据.在实际测试中,注册rdma内存的成本远大于内存拷贝.相比每次发送或接收数据时注册rdma内存.

最好是,用已注册好内存池缓存rdma内存.每次发起请求时,将数据分成多片来接收/发送,每一片数据的最大长度恰好是预先注册好的内存长度,并从内存池中取出注册好的内存,并在内存块和实际数据地址之间做一次拷贝.

RNR与接收缓冲队列

RDMA直接操作远端内存,当远端内存未准备好时,就会触发一次RNR错误,对RNR错误,或断开,或休息一段时间.
显然避免RNR错误是提高RDMA传输性能和稳定度的关键.

coro_rpc用如下策略解决RNR问题:对每个连接,都准备一个接收缓冲队列.队列中含若干块内存(默认8块*256KB),每当收到一块数据传输完成的通知时,在缓冲队列中,立即补充一块新的内存,并把该块内存提交到RDMA接收队列中.

发送缓冲队列

在发送链路中,最天真思路是,先在RDMA缓冲中拷贝数据,再把它提交到RDMA发送队列.当数据写入到对端后,再重复上述步骤发送下一块数据.

上述步骤有两个瓶颈,第一个是如何并行化内存拷贝和网络传输,第二个是,网卡发送完一块数据,再到CPU提交下一块数据的这段时间,网卡实际上是空闲状态,未能最大化利用带宽.

为了提高发送数据,需要引入发送缓冲的概念.每次读写,不等待对端完成写入,而是在将内存提交到RDMA发送队列后就立即完成发送,让上层代码发送下个请求/数据块,直到未完成发送的数据达到发送缓冲队列的上限.

此时才等待发送请求完成,随后在RDMA发送队列中提交新的内存块.

大数据包,使用上述算法可同时内存拷贝和网络传输,同时因为同时发送多块数据,网卡发送完一片数据到应用层提交新数据块的这段时间,网卡可发送另外一块待发送的数据,从而最大化利用了带宽.

小包写入合并

rdma在发送小数据包时吞吐量相对较低.对小包请求,一个既能提高吞吐又不引入额外延迟的思路是按大数据包合并多个小包.

假如应用层提交了一个发送请求,且此时发送队列已满,则数据不会立即发送到远端,而是临时在缓冲中.此时假如应用层又提交了下个请求,则可将这次请求的数据合并写入到上次数据临时的缓冲中,从而实现数据的合并发送.

内联数据

某些rdma网卡对小数据包,可通过内联数据的方式发送数据,它不需要注册rdma内存,同时可取得更好的传输性能.

coro_rpc数据包小于256字节并且网卡支持内联数据时,会用该方式发送数据.

内存消费控制

RDMA通信需要自己管理内存缓冲.当前,coro_rpc默认使用的内存片大小是256KB.接收缓冲初始大小为8,发送缓冲上限为2,因此单连接的内存消费为10*256KB约为2.5MB.

用户可通过调整缓冲的大小缓冲大小来控制内存的消费.

此外,RDMA内存池同样提供水位配置,来控制内存消费上限.当RDMA内存池的水位过高时,试从该内存池中取新内存的连接会失败并关闭.

使用连接池

高并发场景下,可通过coro_rpc提供的连接池复用连接,这可避免重复创建连接.此外,因为coro_rpc支持连接复用,可将多个小数据包请求提交到同一个连接中,实现pipeline发送,并利用底层的小包写入合并技术提高吞吐.

static auto pool = coro_io::client_pool<coro_rpc::coro_rpc_client>::create(conf.url, pool_conf);
auto ret = co_await pool->send_request([&](coro_io::client_reuse_hint, coro_rpc::coro_rpc_client& client) {return client.send_request<echo>("hello");});
if (ret.has_value()) {auto result = co_await std::move(ret.value());if (result.has_value()) {assert(result.value()=="hello");}
}
http://www.dtcms.com/a/334363.html

相关文章:

  • 软件SPI实现(3):SPI协议测试(使用W25Q64)
  • Jenkins常见问题及解决方法
  • 计算机存储器分类和层次结构详解
  • 027 动静态库 —— 静态库
  • Docker数据卷挂载和本地目录挂载
  • 八、SpringBoot项目热部署
  • Java服务自动停止原因及查找方法
  • Cloudflare Tunnels 部署与隧道异常关闭的解决方案
  • 攻击者如何毒害人工智能工具和防御系统
  • 【更新公告】C++算法·线段树
  • CF每日3题(1500-1700)
  • 《WINDOWS 环境下32位汇编语言程序设计》第2章 准备编程环境
  • IO流-序列化流
  • 记录 GMS 认证相关条件
  • 玄机靶场 | 日志分析-Tomcat日志分析
  • AI生成视频开源模型技术解析
  • Rocky Linux 9.2:从 /home 分区释放 10G 空间扩容到 / 根分区
  • AI可行性分析:数据×算法×反馈=成功
  • 【P40 6-3】OpenCV Python——图像融合(两张相同属性的图片按比例叠加),addWeighted()
  • 软考 系统架构设计师系列知识点之杂项集萃(124)
  • 池式结构之连接池
  • pwn定时器,ARM定时delay 外部中断用函数指针(统一)day55,56
  • 数据结构:满二叉树 (Full Binary Tree) 和 完全二叉树 (Complete Binary Tree)
  • 安卓定制开机动画的bootanimation.zip的注意点
  • (论文阅读)FedViT:边缘视觉转换器的联邦持续学习
  • 美国服务器环境下Windows容器工作负载基于指标的自动扩缩
  • Java驾驭金融风暴:大数据+机器学习重塑资产配置与风险平衡
  • CPP多线程3:async和future、promise
  • 【八股】计网-计算机网络-秋招
  • 让数据库交互更优雅:MyBatis核心机制深度解析(附实战视频教程)