【RDMA】RDMA编程 和相关资料

目录

RDMA的学习环境搭建

RDMA与socket的类比

RDMA编程流程

RDMA编程2

RDMA学习路线总结

 简介--什么是rdma

编程环境

推荐编程库

编程参考手册

相关资料和代码参考

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就行了

终于可以开始进行数据传输了 ==== (如何传输下篇再说)


4. 关闭连接

  1. 断开连接
    rdma_get_cm_event返回RDMA_CM_EVENT_DISCONNECTED事件时,表示客户端断开了连接,server端要进行对应的清理。此时可以调用rdma_ack_cm_event释放事件资源。然后依次调用下面的函数,释放连接资源,内存资源,队列资源。

  2. rdma_disconnect

  3. rdma_destroy_qp

  4. ibv_dereg_mr

  5. rdma_destroy_id
    释放同客户端连接的rdma_cm_id

  6. rdma_destroy_id
    释放用于侦听的rdma_cm_id

  7. rdma_destroy_event_channel
    释放 event channel

原文:RDMA编程1 建立侦听_winux的专栏-CSDN博客

图链接

“rdma event channel”的图片搜索结果


《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.openfabrics.org/downloads/Media/SC11/SC11_Writing_Application_Programs_for_RDMA_using_OFA_Software-v5.pdf

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)

  1. dev_list = ibv_get_device_list(NULL);获取主机可用的VPI设备列表
  2. ib_dev = dev_list[0]默认取第一个设备
  3. ibv_context* context = ibv_open_device(ib_dev);打开设备获取context
  4. ibv_pd* pd = ibv_alloc_pd(context);创建Protection Domain
  5. worker_env_ (worker_env)拷贝工作环境参数
  6. event_channel_ = ibv_create_comp_channel(context_);创建完成通道,用于通知完成队列
  7. cq_ = ibv_create_cq(context_, MAX_CONCURRENT_WRITES * 2, NULL, event_channel_, 0);创建完成队列
  8. ibv_req_notify_cq(cq_, 0)完成完成队列与完成通道的关联
  9. 启动处理线程Process_CQ()

~RdmaAdapter()

  1. ibv_destroy_cq(cq_)
  2. ibv_destroy_comp_channel(event_channel_)
  3. ibv_dealloc_pd(pd_)
  4. ibv_close_device(context_)


void Process_CQ()

  1. ibv_get_cq_event(event_channel_, &cq, &cq_context)阻塞等待队列中进入新元素
  2. ibv_ack_cq_events(cq, 1);确认收到的事件
  3. ibv_req_notify_cq(cq_, 0)重新注册,等待下次事件触发
  4. int ne = ibv_poll_cq(cq\_, MAX_CONCURRENT_WRITES * 2, static_cast<ibv_wc*>(wc_)); 从CQ队列中获取所有的事件,ne表示事件个数
  5. 遍历每个cqe
    1. 判断wc_[i].status == IBV_WC_SUCCESS,检查wr的状态是否正确
    2. 若wc_[i].opcode == IBV_WC_RECV_RDMA_WITH_IMM
      1. RdmaChannel* rc = reinterpret_cast


RdmaChannel


RdmaChannel(const RdmaAdapter* adapter, const string local_name, const string remote_name_)

  1. qp_ = ibv_create_qp(adapter_->pd_, &attr); 创建Queue Pair
  2. ibv_modify_qp(qp_, &attr, mask) 初始化QP
  3. 创建4个buffer并建立hash,同时加入索引表,tx_message_buffer_ = new RdmaMessageBuffer(this, buffer_names[0]);
  4. 执行100次Recv() (ibv_post_recv()),使得buffer准备好接收。


~RdmaChannel()

  1. ibv_destroy_qp(qp_) 销毁QP
  2. 销毁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是最新版本,详情参考:

Linux InfiniBand Drivers ,

    除了安装版本,最好下载相关源码,里面有相关参考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

相关资料和代码参考

www.mellanox.com/

RDMAmojo - RDMAmojo - blog on RDMA technology and programming by Dotan Barak RDMAmojo

samplecode: https://github.com/tarickb/the-geek-in-the-corner 

代码解析The Geek in the Corner | Programming odds and ends — InfiniBand, RDMA, and low-latency networking for now. | Page 2

rdma网络课程培训

迈络思网关给出了rdma网络编程培训的相关课程,可以作为相关参考http://academy.mellanox.com/en/

迈络思相关硬件的配置工具

mellanox官网给出的参考资料

详情请见: Configuration Tools

作者:胡宇辉,某券商软件开发工程师,主要从事后台高性能服务端编程,分布式系统设计。使用语言C/C++, Erlang,Golang,了解ELK, open-falcon, RDMA等相关知识点。

RDMA学习路线总结 - sysu_huyh5的个人页面 - OSCHINA - 中文开源技术交流社区

posted on 2022-10-04 01:24  bdy  阅读(288)  评论(0编辑  收藏  举报

导航