一线攻城狮实战经验:RDMA,好用却又很难用?

势不可挡的 RDMA

现在,服务器的网络带宽愈来愈高。当网络带宽迈过万兆这条线后,操做系统用于处理网络IO的开销就愈来愈难以忽视。在一些网络IO密集的业务中,操做系统自己成为了网络通讯的瓶颈,这不只会致使调用时延的增长(尤为是长尾),还会影响到服务的总体吞吐。git

相对于网络带宽的发展速度,CPU性能的发展停滞是致使上述问题的主要缘由。 所以,想从根本上解决CPU参与网络传输的低效问题,就要更多地借助专用芯片的能力,RDMA高性能网络势不可挡。 github

RDMA(Remote Direct Memory Access),能够简单理解为网卡彻底绕过CPU实现两个服务器之间的内存数据交换。其做为一种硬件实现的网络传输技术,能够大幅提高网络传输效率,帮助网络IO密集的业务(好比分布式存储、分布式数据库等)得到更低的时延以及更高的吞吐。数据库

具体来讲,RDMA技术的应用要借助支持RDMA功能的网卡以及相应的驱动程序。由下图所示,一旦应用程序分配好资源,其能够直接把要发送的数据所在的内存地址和长度信息交给网卡。网卡从内存中拉取数据,由硬件完成报文封装,而后发送给对应的接收端。接收端收到RDMA报文后,直接由硬件解封装,取出数据后,直接放在应用程序预先指定的内存位置。apache

**因为整个IO过程无需CPU参与,无需操做系统内核参与,没有系统调用,没有中断,也无需内存拷贝,所以RDMA网络传输能够作到极高的性能。**在极限benchmark测试中,RDMA的时延能够作到1us级别,而吞吐甚至能够达到200G。编程

RDMA技术说明

**须要注意的是,****RDMA的使用须要应用程序的代码配合(RDMA编程)。**与传统TCP传输不一样,RDMA并无提供socket API封装,而是要经过verbs API来调用(使用libibverbs)。出于避免中间层额外开销的考虑,verbs API采用了贴近硬件实现的语义形态,致使使用方法与socket API差别巨大。 所以,对大多数开发者来讲,不管是改造原有应用程序适配RDMA,仍是写一个全新的RDMA原生的应用程序,都不容易。服务器

RDMA 编程难在哪里?

如图所示,在socket API中,发送接收数据主要用到的接口以下:网络

Socket API多线程

其中,write和read操做中的fd是标识一个链接的文件描述符。应用程序要发送的数据,会经过write拷贝到系统内核缓冲区中;而read实际上也是从系统内核缓冲区中将数据拷贝出来。 在绝大多数应用程序里,一般都会设置fd为非阻塞的,也就是说,若是系统内核缓冲区已满,write操做会直接返回;而若是系统内核缓冲区为空,read操做也会直接返回。 为了在第一时间获知内核缓冲区的状态变化,应用程序须要epoll机制来监听EPOLLIN和EPOLLOUT事件。若是epoll_wait函数因这些事件返回,则能够触发下一次的write和read操做。这就是socket API的基本使用方法。 做为对比,在verbs API中,发送接收数据主要用到的接口以下:框架

Verbs API机器学习

其中,ibv_是libibverbs库中函数和结构体的前缀。ibv_post_send近似于发送操做,ibv_post_recv近似于接收操做。发送接收操做里面的qp(queue pair)近似于socket API里面的fd,做为一个链接对应的标识。wr(work request)这个结构体里包含了要发送/接收的数据所在的内存地址(进程的虚拟地址)和长度。ibv_poll_cq则做为事件检测机制存在,相似于epoll_wait。

乍一看去,RDMA编程彷佛很简单,只要把上述函数替换了就能够。但事实上,上述的对应关系都是近似、相似,而不是等价。 关键区别在于,socket API都是同步操做,而RDMA API都是异步操做(注意异步和非阻塞是两个不一样的概念)

具体而言,ibv_post_send函数返回成功,仅仅意味着成功地向网卡提交了发送请求,并不保证数据真的被发送出去了。若是此时立马对发送数据所在的内存进行写操做,那么发送出去的数据就极可能是不正确的。socket API是同步操做,write函数返回成功,意味着数据已经被写入了内核缓冲区,虽然此时数据未必真的发送了,但应用程序已经能够随意处置发送数据所在的内存。

另外一方面,ibv_poll_cq所获取的事件,与epoll_wait获取的事件也是不一样的。前者代表,以前提交给网卡的某一发送或接收请求完成了;然后者表示,有新的报文被成功发送或是接收了。这些语义上的变化会影响到上层应用程序的内存使用模式和API调用方式。

除了同步、异步的语义区别外, RDMA编程还有一个关键要素,即全部参与发送、接收的数据,所在的内存必须通过注册

所谓内存注册,简单理解,就是把一段内存的虚拟地址和物理地址间的映射关系绑定好之后注册给网卡硬件。这么作的缘由在于,发送请求和接收请求所提交的内存地址,都是虚拟地址。只有完成内存注册,网卡才能把请求中的虚拟地址翻译成物理地址,才能跳过CPU作直接内存访问。内存注册(以及解注册)是一个很慢的操做,实际应用中一般须要构建内存池,经过一次性注册、重复使用来避免频繁调用注册函数。

关于RDMA编程,还有不少细节是普通网络编程所不关心的(好比流控、TCP回退、非中断模式等等),这里就不一一展开介绍了。 总而言之,RDMA编程并非一件容易的事情。那么,如何才能让开发者快速用上RDMA这样的高性能网络技术呢?

见招拆招,在brpc中使用RDMA

上面说了不少socket API和verbs API的对比,主要仍是为了陪衬RDMA编程自己的复杂度。事实上,在实际生产环境中,直接调用socket API进行网络传输的业务并很少,绝大多数都经过rpc框架间接使用socket API。一个完整的rpc框架,须要提供一整套网络传输的解决方案,包括数据序列化、错误处理、多线程处理等等。 brpc是百度开源的一个基于C++的rpc框架,其相对于grpc更适用于有高性能需求的场景。在传统TCP传输之外,brpc也提供了RDMA的使用方式,以进一步突破操做系统自己的性能限制。有关具体的实现细节,感兴趣的朋友能够参见github上的源码(https://github.com/apache/incubator-brpc/tree/rdma)。

brpc client端使用RDMA

brpc server端使用RDMA

上面分别列出了brpc中client和server使用RDMA的方法,即在channel和server建立时,把use_rdma这个option设置为true便可(默认是false,也就是使用TCP)。

是的,只需这两行代码。若是你的应用程序自己基于brpc构建,那么从TCP迁移到RDMA,几分钟就够了。固然,在上述quick start以后,若是有更高级的调优需求,brpc也提供了一些运行时的flag参数可调整,好比内存池大小、qp/cq的大小、轮询替代中断等等。

下面经过echo benchmark说明brpc使用RDMA的性能收益(能够在github代码中的rdma_performance目录下找到该benchmark)。在25G网络的测试环境中,对于2KB如下的消息,使用RDMA后,server端的最大QPS提升了50%以上,200k的QPS下平均时延降低了50%以上。 

Echo benchmark下server端最大QPS(25G网络)

Echo benchmark在200k QPS下的平均时延(25G网络)

RDMA对echo benchmark的性能收益仅做为参考。实际应用程序的workload与echo相差巨大。对于某些业务,使用RDMA的收益可能会小于上述值,由于网络部分的开销仅占到其业务开销的一部分。但对于另外一些业务,因为避免了内核操做对业务逻辑的干扰,使用RDMA的收益甚至会高于上述值。这里举两个应用brpc的例子:

  • 在百度分布式块存储业务中,使用RDMA相比于使用TCP,4KB fio时延测试的平均值降低了约30%(RDMA仅优化了网络IO,存储IO则不受RDMA影响)。

  • 在百度分布式内存KV业务中,使用RDMA相比于使用TCP,200k QPS下,单次查询30key的平均时延降低了89%,而99分位时延降低了96%。

RDMA 须要基础设施支持

RDMA是一种新兴的高性能网络技术,对于通讯两端都可控的数据中心内网络IO密集业务,如HPC、机器学习、存储、数据库等,意义重大。咱们鼓励相关业务的开发者关注RDMA技术,尝试利用brpc构建本身的应用以平滑迁移至RDMA。 可是,须要指出的是,RDMA当前还没法像TCP那样通用,有一些基础设施层面的限制须要注意:

  • RDMA须要网卡硬件支持。常见的万兆网卡通常不支持这项技术。

  • RDMA的正常使用有赖于物理网络支持。

百度智能云在RDMA基础设施方面积累了深厚的经验。得益于先进的硬件配置与强大的工程技术,用户能够在25G甚至是100G网络环境中,经过物理机或容器,充分获取RDMA技术带来的性能收益,而将与业务无关的复杂的物理网络配置工做(好比无损网络PFC以及显示拥塞通告ECN),交给百度智能云技术支持人员。欢迎对高性能计算、高性能存储等业务有需求的开发者向百度智能云咨询相关状况。 

本文做者李兆耕,百度系统部资深研发工程师,长期关注高性能网络技术,负责百度RDMA研发工做,覆盖从上层业务调用到底层硬件支持的全技术栈。

本文由百度开发者中心发布,一个面向开发者的知识分享平台,专一于为开发者打造一个有温度的技术交流社区,开发者经过平台来分享知识、相互交流。 developer 发布!

相关文章
相关标签/搜索