文档章节

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

百度开发者中心
 百度开发者中心
发布于 01/21 12:08
字数 2961
阅读 3.3W
收藏 61

势不可挡的 RDMA

如今,服务器的网络带宽越来越高。当网络带宽迈过万兆这条线后,操作系统用于处理网络IO的开销就越来越难以忽视。在一些网络IO密集的业务中,操作系统本身成为了网络通信的瓶颈,这不仅会导致调用时延的增加(尤其是长尾),还会影响到服务的整体吞吐。

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

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

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

**由于整个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 发布!

© 著作权归作者所有

百度开发者中心
粉丝 22
博文 3
码字总数 12963
作品 0
昌平
私信 提问
加载中

评论(13)

超级大丁丁
超级大丁丁
这个有点牛逼
f
freezingsky
是不是有点像GPU,解决CPU计算,由CPU计算和渲染。所以, 网卡那一块应该属于带U的硬件?
TGVvbmFyZA
TGVvbmFyZA
IB卡就會繞過CPU
亡灵序曲
亡灵序曲
安全性呢
ExtremeTalk
ExtremeTalk
解放了程序员也解决了程序员
d
dwcz
是不是忘了什么啊?网络传输的可信度没本机高,既然加硬件就应该提高安全度。
W
WindSpeed
硬件不支持是不能用的,局限性还是很大
晒太阳的小猪
晒太阳的小猪
网卡也要加内存和CPU能力啦
_snake_
_snake_
就是由专门负责网络的芯片来分担CPU对IO的处理,没毛病。
斯武丶风晴
斯武丶风晴
Dma升级
据说,攻城狮也可以像设计狮一样切图了?

为了方便新入坑的UI设计狮和前端开发攻城狮能更顺畅的看完这篇文章,首先,先来简单科普一下到底什么是切图(老油条可直接忽略)? 通俗的说,切图就是把设计稿切成一片片的,然后前端攻城狮...

mo311
2018/10/10
88
0
利用redis replication实现redis服务器热迁移

利用redis replication实现redis服务器热迁移 文章开头我先声明:标题过于高大上,主要是为了装逼。 某个月黑风高的夜晚,一只运维攻城狮和一只PHP程序猿在促膝长谈,只见PHP程序猿双眼目光呆...

烟头网管
2015/05/06
0
0
OSC 第 107 期高手问答 —— Kubernetes 与容器集群管理

OSCHINA 本期高手问答( 1月6日- 1月12日)我们请来了时速云开发工程师 @Oscarzhaosl 来解答 Kubernetes 与容器集群管理 方面的问题。 赵帅龙,@Oscarzhaosl ,容器云平台后端攻城狮,kuberne...

叶秀兰
2016/01/05
3.7K
13
【线上】cSphere希云 Docker实战之入门以及Dockerfile

这是一个面向全国代码劳动人民的 线上活动 哦,对Docker感兴趣的Oscers们接皂,不客气:) 第一期课程:Docker实战之入门以及Dockerfile 开课时间: 2015.06.03 21:00-23:00 互动时间 23:00-...

文洁洁洁
2015/05/27
5.4K
19
红薯微剧场 | 开源众包发包记第一集 —— 前端篇

开源众包发包记 ---玩转众包 第一集 巧引外援、顺度难关---前端开发项目篇 丁酉年11月,北京的天气已经逐渐寒凉,部分办公司的灯光已熄灭,办公室的窗户上印衬着佳佳略显倦怠的容颜。虽然小风...

王练
2018/06/07
2.4K
4

没有更多内容

加载失败,请刷新页面

加载更多

初学数据结构--堆和优先队列

初学数据结构--堆和优先队列 在之前的那两章详细的向各位介绍了二分搜索树这种数据结构,同时我们使用二分搜索树实现了集合和映射这两个相对来讲更加高层的数据结构。那么树,这种数据结构本...

loubobooo
14分钟前
43
0
Elasticsearch7.3.2下载安装

1. es镜像下载 https://thans.cn/mirror/elasticsearch.html 2. rz上传到/usr/local 3. 解压 tar -zxf elasticsearch-7.3.2-linux-x86_64.tar.gz 4. 配置elasticsearch.yml cd /usr/local......

joininjoy
16分钟前
34
0
iOS面试题--性能优化篇

1.造成tableView卡顿的原因有哪些? 1.最常用的就是cell的重用, 注册重用标识符 如果不重用cell时,每当一个cell显示到屏幕上时,就会重新创建一个新的cell 如果有很多数据的时候,就会堆积...

G_
23分钟前
44
0
第 430 期 Python 周刊

文章,教程和讲座 使你的 Python 程序运行快一点 链接: https://martinheinz.dev/blog/13 不喜欢 Python 语言的人总是说它的运行速度很慢。对于特定的程序(无论使用何种编程语言), 它的快慢...

iCodeBugs
33分钟前
75
0
Linux中修改环境变量及生效方法

Linux中修改环境变量及生效方法 方法一:   在/etc/profile文件中添加变量【对所有用户生效(永久的)】   用VI在文件/etc/profile文件中增加变量,该变量将会对Linux下所有用户有效,并且...

突突突酱
34分钟前
34
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部