RDMA编程养成记

高性能分布式文件系统FastCFS从今年7月份开始适配RDMA 网络,经过4个多月的预研、开发和测试,通过 ibverbs和rdmacm原生支持RDMA的FastCFS 5.0于11月22日发布。

RDMA编程初学者可以了解一下RDMA概念及相关介绍:《初识RDMA技术——RDMA概念,特点,协议,通信流程》。RDMA网络环境可以租用阿里云的第四代神龙架构服务器,如c8y,g8y等,在ECS租用页面记得要勾选“弹性RDMA接口”。

一、RDMA 快速入门

1. 使用perftest测试工具

CentOS和RHEL等Linux发行版:yum install perftest -y

Ubuntu和Debian:apt install perftest -y

perftest提供的测试程序将server和client合为一体,通过命令行参数区分,分别在两台服务器执行,先在一台机器执行 server,然后再另外一台机器执行 client。

消息收发机制的两个测试命令如下:

  ib_send_bw:测试网络带宽

  ib_send_lat:测试网络延迟

ib_send_bw 和 ib_send_lat 的参数基本一致,以ib_send_bw为例:

  server端: ib_send_bw -R -d mlx5_1 -s 4096 -D 60

  client端: ib_send_bw -R -d mlx5_1 -s 4096 -D 60 172.16.168.100

参数说明:

  -d mlx5_1 指定设备名称,可以通过命令 ibv_devices 或者 ibv_devinfo 获得设备名称;

  -s 4096 为消息大小;

  -D 60 为测试时长,单位为秒;

  -R 或 --rdma_cm,表示使用rdmacm建连;

  172.16.168.100为 server端 RDMA 网卡的IP地址,修改为对应的 IP 地址即可。

2. 编译和执行 demo 程序

CentOS和RHEL等Linux发行版:yum install rdma-core-devel -y

Ubuntu和Debian:apt install libibverbs-dev librdmacm-dev -y

我们采用ibverbs的消息收发机制来传输数据:包括send和receive操作。在网上找到的RDMA编程demo非常实用:

《RDMA编程之服务端 server demo》,将源码复制下来,保存为 rdma_server_test.c。

《RDMA 编程客户端client demo》,将源码复制下来,保存为 rdma_client_test.c。

或者直接获取我们完善后的代码:

  curl -o rdma_server_test.c http://www.fastken.com/test/rdma_server_test.c

  curl -o rdma_client_test.c http://www.fastken.com/test/rdma_client_test.c

编译命令如下:

  gcc -Wall -g -O3 -o rdma_server_test rdma_server_test.c -lrdmacm -libverbs -lpthread

  gcc -Wall -g -O3 -o rdma_client_test rdma_client_test.c -lrdmacm -libverbs -lpthread

执行测试程序:

    server端:./rdma_server_test

    client 端:./rdma_client_test  serverip  serverport

    例如:./rdma_client_test  172.16.168.100  12345

二、FastCFS如何适配RDMA

为了同时支持socket和RDMA两种通信方式,我们把RDMA相关操作封装在底层库 libfastrdma中,基础库 libfastcommon 和网络库 libserverframe通过dlopen和dlsym来调用libfastrdma提供的API,这样就做到了对libfastrdma的弱依赖。

libfastrdma采用ibverbs和rdmacm提供的API,通过ibv_post_send发送数据,通过 ibv_post_recv接收数据。RDMA的数据收发buffer需要通过ibv_reg_mr注册,对应的API为:struct ibv_mr *ibv_reg_mr(struct ibv_pd *pd, void *addr, size_t length, int access);

我们采用对象池的做法,事先分配好buffer并调用ibv_reg_mr进行注册。第一个参数pd没必要每次调用时动态创建,完全可以全局共享,一个RDMA网络设备只需要分配一个pd。在我们的网络框架中,一个连接的网络收发 buffer 通常只有一个(发送和接收共用一个buffer)。

为了避免内存拷贝(即数据零拷贝),RDMA收发数据直接使用ibv_reg_mr注册的buffer,并且数据发送和接收均为异步模式,这个机制和 socket 相比存在如下两个挑战:

  1. 发送和接收buffer何时才能被回收利用的问题。如果采用单个buffer,则表现为发送和接收重入问题;

  2. 发送完成通知(opcode 为IBV_WC_SEND)不保证时序的问题。通过实测,发送完成通知不是实时的,非常慢。比如先调用send,然后调用recv,往往会先收到对方回复的数据,然后才收到发送完成通知。在批量(连续)推送数据场景,如果收到IBV_WC_SEND后再进行下一次发送,性能惨不忍睹。

我们采用一问一答的单向请求模式,简单高效地解决了上述问题。这种模式类似传统的Client/Server同步请求模型,即Client向Server发送请求,然后等待响应,收到server响应后,才能发起下次请求。那么Server要主动向Client发起请求(比如推送数据)该怎么办呢?很简单,Server再建立到Client的一个连接就好(建连动作可以由Client发起),这样就能保证单向请求模式。

三、RDMA编程问题排查

RDMA API的出错信息明显存在营养不良的问题,具体原因基本靠猜。帮我解决问题的一个高手点评:“rdma是我用过的最坑的api”。下面分享四个RDMA编程过程中踩到的坑。

案例1、RDMA相关指针不能跨进程(如父子进程)访问

租用阿里云的 g8y 型号的ECS,在 Alibaba Cloud Linux 3下程序运行正常,而在Ubuntu 18.04和 20.04下,出现下列错误:

ibv_query_port fail, errno: 13, error info: Permission denied

ibv_reg_mr fail, errno: 13, error info: Permission denied

经调试和高手指点才发现是RDMA相关指针(如struct ibv_context *、struct ibv_pd * 等)不能跨进程访问(即在父进程中创建或获取,在子进程中使用)。我们的RDMA初始化代码在daemon_init(这个函数会fork两次成为daemon进程)之前,因此出现上述报错;放到daemon_init之后就没问题了。

案例2、对端没有先调用 ibv_post_recv

ibv_post_send 报错, errno: 12, error info: Cannot allocate memory

案例3、client连接超时,server端报错:

rdma_create_qp fail, errno: 22, error info: Invalid argument

现象:在服务重启的时候有这个报错,后面就正常了。

原因:client 2秒连接超时后关闭连接(释放了rdma id),然后server却收到建连请求了。

吐槽一下,错误码好歹是 EPIPE(32),也比 EINVAL(22)强太多了。

案例4、笔误导致的低级错误

获得 wc 后,其status为 21,通过 ibv_wc_status_str(wc.status) 获得的错误信息:general error

问题代码:buffer->mr = ibv_reg_mr(pd, &buffer->buff, buffer->size,

IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE);

错误原因:第二参数buffer->buff是指针,不应该再用 & 取其地址(抄代码的锅)。

总结

RDMA API 比较简洁,其编程入门容易,完全掌握和排查问题较难。希望这篇文章对大家有所帮助,RDMA和FastCFS相关问题可以加群或者私信交流。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,641评论 6 525
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,754评论 3 408
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 173,075评论 0 370
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,369评论 1 303
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,386评论 6 402
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,800评论 1 317
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,122评论 3 431
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 41,130评论 0 281
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,689评论 1 327
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,693评论 3 348
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,804评论 1 356
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,399评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 43,128评论 3 341
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,528评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,705评论 1 278
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,409评论 3 383
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,878评论 2 368

推荐阅读更多精彩内容

  • linux 内核定时器timer_list用法作者 codercjg 在 30 十月 2015, 2:27 下午 ...
    codercjg阅读 1,029评论 0 0
  • 因为看了一个介绍说低延时,然后就很好奇的去搜了下是怎么做到的,就搜索到了RDMA技术 背景面对高性能计算、大数据分...
    知止9528阅读 10,730评论 0 2
  • Hadoop 常见面试题 mr 工作原理 ☆☆☆☆mr 将得到的split 分配对应的 task,每个任务处理相对...
    hdn040083阅读 3,621评论 0 1
  • 下面为Daytime这个服务的源代码例子,同时兼容IPV6和IPV4的地址,最后部分有更多说明。 单播模式下的Se...
    天楚锐齿阅读 5,710评论 0 2
  • DMA 技术是一个 直接内存访问技术。 在传统的linux 内存读写操作都必须经过cpu,读写寻址都是有cpu 完...
    hcci阅读 577评论 0 0