【RDMA】RDMA编程 和相关资料
目录
RDMA的学习环境搭建
RDMA需要专门的RDMA网卡或者InfiniBand卡才能使用,学习RDMA而又没有这些硬件设备,可以使用一个软件RDMA模拟环境,softiwarp ,
- 这是加载地址:https://github.com/zrlio/softiwarp
- 这是安装教程:Reflections Of The Void: How to install Soft-iWARP on Ubuntu 10.10, AKA how to have RDMA enabled system without the expensive hardware.
这里也有一个RDMA编程的入门示例,
- https://github.com/tarickb/the-geek-in-the-corner
需要注意的是,这个例子里面缺省用的是IPv6连接,如果希望在IPv4环境下测试,需要先改代码用IPv4地址。
参考资料:
RDMA网卡和传统网卡对比说明
【RDMA】RDMA编程和TCP编程的区别|bRPC_bandaoyu的note-CSDN博客_rdma技术
RDMA与socket的类比
和Socket连接类似,RDMA连接也分为可靠连接和不可靠连接。然而也不完全相同,Socket的可靠连接就是TCP连接,是流式的;不可靠连接也就是UDP,是消息式的。对于RDMA来说,无论是可靠连接和不可靠连接,都是消息式的。
编程角度看,RDMA代码也分为Server端,Client端,也有bind, listen, connect, accept,等动作,然而细节上仍有不少区别。
在Server端,一个RDMA服务器的代码流程如下:
(rdma_cm接口,rdma_cm和vbers接口的区别:【RDMA】12. RDMA之Verbs|OFED_bandaoyu的note-CSDN博客)
1 rdma_create_event_channel
这一步是创建一个event channel,event channel是RDMA设备在操作完成后,或者有连接请求等事件发生时,用来通知应用程序的通道。其内部就是一个file descriptor, 因此可以进行poll等操作。
2 rdma_create_id
这一步创建一个rdma_cm_id, 概念上等价与socket编程时的listen socket。
3 rdma_bind_addr
和socket编程一样,也要先绑定一个本地的地址和端口,以进行listen操作。
4 rdma_listen
开始侦听客户端的连接请求
5 rdma_get_cm_event
这个调用就是作用在第一步创建的event channel上面,要从event channel中获取一个事件。这是个阻塞调用,只有有事件时才会返回。在一切正常的情况下,函数返回时会得到一个 RDMA_CM_EVENT_CONNECT_REQUEST事件,也就是说,有客户端发起连接了。
在事件的参数里面,会有一个新的rdma_cm_id传入。这点和socket是不同的,socket只有在accept后才有新的socket fd创建。
6 ibv_alloc_pd
创建一个protection domain。protection domain可以看作是一个内存保护单位,在内存区域和队列直接建立一个关联关系,防止未授权的访问。
(RDMAWorker::listent >> ib.init() >> ProtectionDomain >> ibv_alloc_pd)
7 ibv_create_comp_channel
和之前创建的event channel类似,这也是一个event channel,但只用来报告完成队列里面的事件。当完成队列里有新的任务完成时,就通过这个channel向应用程序报告。
(RDMADispatcher::polling_start >> ib->create_comp_channel >> cc->init >>ibv_create_comp_channel)
8 ibv_create_cq
创建[完成队列],创建时就指定使用第6步的channel。
9 rdma_create_qp
创建一个queue pair, 一个queue pair包括一个发送queue和一个接收queue. 指定使用前面创建的cq作为完成队列。该qp创建时就指定关联到第6步创建的pd上。
10 ibv_reg_mr
注册内存区域。RDMA使用的内存,必须事先进行注册。这个是可以理解的,DMA的内存在边界对齐,能否被swap等方面,都有要求。
11 rdma_accept
至此,做好了全部的准备工作,可以调用accept接受客户端的这个请求了。 –:)长出一口气 ~~ 且慢,
12 rdma_ack_cm_event
对于每个从event channel得到的事件,都要调用ack函数,否则会产生内存泄漏。这一步的ack是对应第5步的get。每一次get调用,都要有对应的ack调用。
13 rdma_get_cm_event
继续调用rdma_get_cm_event
, 一切正常的话我们此时应该得到 RDMA_CM_EVENT_ESTABLISHED 事件,表示连接已经建立起来。不需要做额外的处理,直接rdma_ack_cm_event
就行了
终于可以开始进行数据传输了 ==== (如何传输下篇再说)
-
断开连接
当rdma_get_cm_event
返回RDMA_CM_EVENT_DISCONNECTED事件时,表示客户端断开了连接,server端要进行对应的清理。此时可以调用rdma_ack_cm_event
释放事件资源。然后依次调用下面的函数,释放连接资源,内存资源,队列资源。 -
rdma_disconnect
-
rdma_destroy_qp
-
ibv_dereg_mr
-
rdma_destroy_id
释放同客户端连接的rdma_cm_id -
rdma_destroy_id
释放用于侦听的rdma_cm_id -
rdma_destroy_event_channel
释放 event channel
原文:RDMA编程1 建立侦听_winux的专栏-CSDN博客
《RDMA技术详解(一):RDMA概述》RDMA技术详解(一):RDMA概述_Master-TJ的个人博客-CSDN博客_rdma
《RDMA技术详解(二):RDMA Send Receive操作》RDMA技术详解(二):RDMA Send Receive操作_Master-TJ的个人博客-CSDN博客
《RDMA技术详解(三):理解RDMA Scatter Gather List》RDMA技术详解(三):理解RDMA Scatter Gather List_Master-TJ的个人博客-CSDN博客
creating Scatter Gather Elements
https://www.cs.mtsu.edu/~waderholdt/6430/papers/ibverbs.pdf
RDMA的原理、传输与Verbs RDMA的原理、传输与Verbs - rebeca8 - 博客园
access open 知乎_12. RDMA之Verbs access open 知乎_12. RDMA之Verbs_暴躁的巨锤的博客-CSDN博客
目前有两张硬件可以使用RDMA传输,一个是infiniband,一个是RDMA over Ethernet,由于IB的成本较高,所以RoCE成为一种趋势。
RoCE可以在以太网上运行RDMA协议,时延比普通以太网可以提升30%以上,也可以支持双协议栈,同时用TCP和RDMA,编程过程类似IB。
有两张建链方式,一种是通过RDMA_CM建链,一种是先通过TCP建链,通过tcp通道交换双方的设备信息,QP信息,简历RDMA链路,然后关闭tcp链路,第二种更常用。
RDMA编程流程
vbers 接口:
1)初始化RDMA设备
ibv_get_device_list()获取使用可以使用RDMA传输的设备个数,可以根据ibv_get_device_list结构中的dev_name找到需要使用的设备;
ibv_open_device()打开设备,获取设备句柄;
ibv_query_device()查询设备,获取设备属性
ibv_query_port()查询设备端口属性
如果类型为Ethernet,bv_query_gid()获取设备GID,用于交换双方信息使用
2)创建QP信息
ibv_alloc_pd()用于创建qp接口的参数
ibv_create_cq()创建CQ,一个CQ可以完成的CQE的个数,CQE与队列个数有关,队列多,CQE个数就设置多,否则设置少,一个CQ可以对应一个QP,也可以两个CQ对应一个QP。一个CQ包含发送和接收队列。
ibv_create_qp()创建QP。类似tcp的socket
3)注册MR信息
ibv_reg_mr()注册网卡内存信息,把操作系统物理内存注册到网卡
4)交换QP信息
ibv_modify_qp()交换双方QP信息,修改QP信息状态级
Client端:先创建QP,修改状态级reset到INIT,修改INIT到RTR,然后发送到server端,server端创建QP,修改状态机有INIT到RTR,然后发送到客户端,客户端修改状态机有RTR到RTS,发送到server端,server端修改状态机有RTR到RTS,这样rmda链路简建立成功。
5)发送和接收
ibv_post_recv()接收消息接口
ibv_post_send()发送消息接口
ibv_poll_cq()用于查询cq队列是否有事件产生,如果有调用recv接口接收。
实际例子在perftest中有
RDMA编程2
相关结构体
// structure to save the address of remote channels.
struct RdmaAddress {
uint32_t lid;
uint32_t qpn;
uint32_t psn;
uint64_t snp;
uint64_t iid;
};
// structure to save information for remote memory regions.
struct RemoteMR {
uint64_t remote_addr;
uint32_t rkey;
};
enum BufferStatus { none, idle, busy };
enum Location { local, remote };
enum BufferType { ACK, MESSAGE, TENSOR };
enum RdmaMessageType {
RDMA_MESSAGE_ACK,
RDMA_MESSAGE_BUFFER_IDLE,
RDMA_MESSAGE_BUFFER_REQUEST,
RDMA_MESSAGE_BUFFER_RESPONSE,
RDMA_MESSAGE_TENSOR_REQUEST,
RDMA_MESSAGE_TENSOR_WRITE
};
RdmaAdapter
RdmaAdapter(const WorkerEnv* worker_env)
- dev_list = ibv_get_device_list(NULL);获取主机可用的VPI设备列表
- ib_dev = dev_list[0]默认取第一个设备
- ibv_context* context = ibv_open_device(ib_dev);打开设备获取context
- ibv_pd* pd = ibv_alloc_pd(context);创建Protection Domain
- worker_env_ (worker_env)拷贝工作环境参数
- event_channel_ = ibv_create_comp_channel(context_);创建完成通道,用于通知完成队列
- cq_ = ibv_create_cq(context_, MAX_CONCURRENT_WRITES * 2, NULL, event_channel_, 0);创建完成队列
- ibv_req_notify_cq(cq_, 0)完成完成队列与完成通道的关联
- 启动处理线程Process_CQ()
~RdmaAdapter()
- ibv_destroy_cq(cq_)
- ibv_destroy_comp_channel(event_channel_)
- ibv_dealloc_pd(pd_)
- ibv_close_device(context_)
- ibv_get_cq_event(event_channel_, &cq, &cq_context)阻塞等待队列中进入新元素
- ibv_ack_cq_events(cq, 1);确认收到的事件
- ibv_req_notify_cq(cq_, 0)重新注册,等待下次事件触发
int ne = ibv_poll_cq(cq\_, MAX_CONCURRENT_WRITES * 2, static_cast<ibv_wc*>(wc_));
从CQ队列中获取所有的事件,ne表示事件个数- 遍历每个cqe
- 判断wc_[i].status == IBV_WC_SUCCESS,检查wr的状态是否正确
- 若wc_[i].opcode == IBV_WC_RECV_RDMA_WITH_IMM
- RdmaChannel* rc = reinterpret_cast
RdmaChannel(const RdmaAdapter* adapter, const string local_name, const string remote_name_)
- qp_ = ibv_create_qp(adapter_->pd_, &attr); 创建Queue Pair
- ibv_modify_qp(qp_, &attr, mask) 初始化QP
- 创建4个buffer并建立hash,同时加入索引表,tx_message_buffer_ = new RdmaMessageBuffer(this, buffer_names[0]);
- 执行100次Recv() (ibv_post_recv()),使得buffer准备好接收。
- ibv_destroy_qp(qp_) 销毁QP
- 销毁buffer
TensorFlow中rdma的使用1_QiangLi的专栏-CSDN博客
RDMA学习路线总结
本博客仅作为分享本人学习rdma技术过程中一些经验和资料分享,若有错误之处,还请指教。如有侵犯版权问题,请立即通知本人,本人立即删除.特此声明!
简介--什么是rdma
【RDMA】技术详解(一):RDMA概述_bandaoyu的博客-CSDN博客_rdma
RDMA(Remote Direct Memory Access)技术全称远程直接数据存取。
RDMA (Remote DMA) is the ability of accessing (i.e. reading from or writing to) memory on a remote machine withoutinterrupting the processing of the CPU(s) on that system.
RDMA的好处与优势:
1、零拷贝(zero-copy) RDMA transfers data directly from user virtual memory on one node to user virtual memory on another node, tcp copies into/out of system buffers on both nodes.
2、CPU占有率( Low CPU utilization) 鉴于zero-copy的存在,使得机器的cpu占有率下降,让cpu更多的执行其他逻辑计算指令。
3、异步事件(Asynchronous operation) rdma在io操作过程中并不阻塞相关线程,tcp/ip确是阻塞方式(此处所说的阻塞,是指tcp将数据发送到内核缓冲区是阻塞的,不同于tcp的noblocking的概念)
RDMA是asynchronous的,即no blocking during a transfer, which – starts when metadata added to “work queue” – finishes when status available in “completion queue”
tcp/ip中是synchronous的,即send(), recv() block until data copied – O_NONBLOCK, MSG_DONTWAIT are not asynchronous,they are “try” and get error
4、Message boundaties preserved. rdma是基于消息模式的,本身保留了消息边界,不同于tcp/ip流传输方式,需要做拆包解包操作。
rdma对于高性能的网络通讯来说,优势很多,但学习成本以及相关推广成本也是蛮高的,后面分享下本人摸索过程中的一些资料。
编程环境
网络环境分为一下几种: InfiniBand环境,iWarp(internet Wide Area RMDA Protocol)环境, RoCE(RDMA over Converged Ethernet)环境,SoftRoCE环境。
在没有硬件设备的支持下,我们可以搭一套软环境来熟悉相关rdma编程的知识点,至于如何搭建一套SoftRoCE环境,请参见本人和小伙伴通过摸索亲测有效的博客
rdma 在 centos 7上面的编译安装 - sysu_huyh5的个人页面 - OSCHINA - 中文开源技术交流社区
推荐编程库
MLNX_OFED 4.0 , 一般来说,就本人个人经验来看,rdma编程最好还是使用硬件厂商的相关库,一般IB网络我们使用Mellanox的硬件(网卡,交换机等等),因此编程所用驱动、代码库还是推荐迈络思OFED,目前为止4.0是最新版本,详情参考:
除了安装版本,最好下载相关源码,里面有相关参考demo供大家学习理解rdma编程。
主要熟悉libibverbs和librdmacm库,其中librdmacm在libibverbs上封装了一层,个人推荐直接使用libibverbs作为初期学习之用,这样更好了解整个事件的来龙去脉。
编程参考手册
RDMA Aware Networks Programming User Manual 1.7, 目前最新版就是1.7版本,此手册可研读多次,对基本概念性了解很有帮助
http://www.mellanox.com/related-docs/prod_software/RDMA_Aware_Programming_user_manual.pdf
相关资料和代码参考
RDMAmojo - RDMAmojo - blog on RDMA technology and programming by Dotan Barak RDMAmojo
samplecode: https://github.com/tarickb/the-geek-in-the-corner
rdma网络课程培训
迈络思网关给出了rdma网络编程培训的相关课程,可以作为相关参考http://academy.mellanox.com/en/
迈络思相关硬件的配置工具
mellanox官网给出的参考资料
详情请见: Configuration Tools
作者:胡宇辉,某券商软件开发工程师,主要从事后台高性能服务端编程,分布式系统设计。使用语言C/C++, Erlang,Golang,了解ELK, open-falcon, RDMA等相关知识点。