天天看點

【RDMA】技術詳解(二):Send Receive操作

1. 前言

RDMA指的是遠端直接記憶體通路,這是一種通過網絡在兩個應用程式之間搬運緩沖區裡的資料的方法。RDMA與傳統的網絡接口不同,因為它繞過了作業系統。這允許實作了RDMA的程式具有如下特點:

  • 絕對的最低延遲時間
  • 最高的吞吐量
  • 最小的CPU足迹 (也就是說,需要CPU參與的地方被最小化)

2. RDMA Verbs操作

使用RDMA, 我們需要有一張實作了RDMA引擎的網卡。我們把這種卡稱之為HCA(主機通道擴充卡)。 擴充卡建立一個貫穿PCIe總線的從RDMA引擎到應用程式記憶體的通道。一個好的HCA将在導線上執行的RDMA協定所需要的全部邏輯都在硬體上予以實作。這包括分組,重組以及流量控制和可靠性保證。是以,從應用程式的角度看,隻負責處理所有緩沖區即可。

【RDMA】技術詳解(二):Send Receive操作

在RDMA中我們使用核心态驅動建立一個資料通道。我們稱之為指令通道(Command Channel)。使用指令通道,我們能夠建立一個資料通道(Data Channel),該通道允許我們在搬運資料的時候完全繞過核心。一旦建立了這種資料通道,我們就能直接讀寫資料緩沖區。

建立資料通道的API是一種稱之為"verbs"的API。“verbs” API是由一個叫做OFED的Linux開源項目維護的。在站點www.openfabrics.org上,為Windows WinOF提供了一個等價的項目。“verbs” API跟你用過的socket程式設計API是不一樣的。但是,一旦你掌握了一些概念後,就會變得非常容易,而且在設計你的程式的時候更簡單。

2. Queue Pairs

RDMA操作開始于“搞”記憶體。當你在對記憶體進行操作的時候,就是告訴核心這段記憶體名花有主了,主人就是你的應用程式。于是,你告訴HCA,就在這段記憶體上尋址,趕緊準備開辟一條從HCA卡到這段記憶體的通道。我們将這一動作稱之為注冊一個記憶體區域(MR)。一旦MR注冊完畢,我們就可以使用這段記憶體來做任何RDMA操作。在下面的圖中,我們可以看到注冊的記憶體區域(MR)和被通信隊列所使用的位于記憶體區域之内的緩沖區(buffer)。

【RDMA】技術詳解(二):Send Receive操作

RDMA硬體不斷地從工作隊列(WQ)(=發送隊列+接收隊列,WQ=SQ+RQ)中去取工作請求(WR)來執行,執行完了就給完成隊列(CQ)中放置工作完成通知(WC,即CQE)。這個WC意思就是Work Completion。表示這個WR RDMA請求已經被處理完成,可以從這個Completion Queue從取出來,表示這個RDMA請求已經被處理完畢。

RDMA通信基于三條隊列(SQ, RQ和CQ)組成的集合。 其中, 發送隊列(SQ)和接收隊列(RQ)負責排程工作,他們總是成對被建立,稱之為隊列對(QP)。當放置在工作隊列上的WR被完成的時候,HCA就建立一個完成隊列元素(CQE)并放置到完成隊列(CQ)中去。

當使用者把WR放置到工作隊列的時候,就意味着告訴HCA緩沖區有需要被發送或者用來接受資料。工作請求(WR)也成為工作隊列元素(WQE), WQE的發音為"WOOKIE",就像星球大戰裡的猛獸。一個WQE主要包含一個指向某個緩沖區的指針。

一個放置在發送隊列(SQ)裡的WQE中包含一個指向待發送的消息的指針。

一個放置在接受隊列裡的WQE裡的指針指向一段緩沖區,該緩沖區用來存放待接受的消息。

下面我們來看一下RDMA中的Work Request(SendWR和ReceWR)

RDMA Send Work Request請求

struct ibv_send_wr {
uint64_t                wr_id;
struct ibv_send_wr     *next;
struct ibv_sge         *sg_list;
int                     num_sge;
enum ibv_wr_opcode      opcode;
int                     send_flags;
uint32_t                imm_data;       /* in network byte order */
union {
struct {
uint64_t        remote_addr;
uint32_t        rkey;
            } rdma;
struct {
uint64_t        remote_addr;
uint64_t        compare_add;
uint64_t        swap;
uint32_t        rkey;
            } atomic;
struct {
struct ibv_ah  *ah;
uint32_t        remote_qpn;
uint32_t        remote_qkey;
            } ud;
    } wr;
};
      

RDMA Receive Work Request請求

struct ibv_recv_wr {
uint64_t                wr_id;
struct ibv_recv_wr     *next;
struct ibv_sge         *sg_list;
int                     num_sge;
};
      

RDMA是一種異步傳輸機制。是以我們可以一次性在工作隊列裡放置好多個發送或接收WQE。HCA将盡可能快地按順序處理這些WQE。當一個WQE被處理了,那麼資料就被搬運了。 一旦傳輸完成,HCA就建立一個完成隊列元素(CQE)并放置到完成隊列(CQ)中去。 相應地,CQE的發音為"COOKIE"。

RDMA Complete Queue Element

struct ibv_wc {
uint64_t                wr_id;
enum ibv_wc_status      status;
enum ibv_wc_opcode      opcode;
uint32_t                vendor_err;
uint32_t                byte_len;
uint32_t                imm_data;       /* in network byte order */
uint32_t                qp_num;
uint32_t                src_qp;
int                     wc_flags;
uint16_t                pkey_index;
uint16_t                slid;
uint8_t                 sl;
uint8_t                 dlid_path_bits;
};
      

3. RDMA Send/Receive

讓我們看個簡單的例子。在這個例子中,我們将把一個緩沖區裡的資料從系統A的記憶體中搬到系統B的記憶體中去。這就是我們所說的消息傳遞語義學。接下來我們要講的一種操作為SEND,是RDMA中最基礎的操作類型。

清晰圖在:Quick Concepts Part 1 – Introduction to RDMA | ZCopy

3.1 第一步

第1步:系統A和B都建立了他們各自的QP的完成隊列(CQ), 并為即将進行的RDMA傳輸注冊了相應的記憶體區域(MR)。 系統A識别了一段緩沖區,該緩沖區的資料将被搬運到系統B上。系統B配置設定了一段空的緩沖區,用來存放來自系統A發送的資料。

【RDMA】技術詳解(二):Send Receive操作

3.2 第二步

第二步:系統B建立一個WQE并放置到它的接收隊列(RQ)中。這個WQE包含了一個指針,該指針指向的記憶體緩沖區用來存放接收到的資料。系統A也建立一個WQE并放置到它的發送隊列(SQ)中去,該WQE中的指針執行一段記憶體緩沖區,該緩沖區的資料将要被傳送。

【RDMA】技術詳解(二):Send Receive操作

3.3 第三步

第三步:系統A上的HCA總是在硬體上幹活,看看發送隊列裡有沒有WQE。HCA将消費掉來自系統A的WQE, 然後将記憶體區域裡的資料變成資料流發送給系統B。當資料流開始到達系統B的時候,系統B上的HCA就消費來自系統B的WQE,然後将資料放到該放的緩沖區上去。在高速通道上傳輸的資料流完全繞過了作業系統核心。

【RDMA】技術詳解(二):Send Receive操作

3.4 第四步

第四步:當資料搬運完成的時候,HCA會建立一個CQE。 這個CQE被放置到完成隊列(CQ)中,表明資料傳輸已經完成。HCA每消費掉一個WQE, 都會生成一個CQE。是以,在系統A的完成隊列中放置一個CQE,意味着對應的WQE的發送操作已經完成。同理,在系統B的完成隊列中也會放置一個CQE,表明對應的WQE的接收操作已經完成。如果發生錯誤,HCA依然會建立一個CQE。在CQE中,包含了一個用來記錄傳輸狀态的字段。

【RDMA】技術詳解(二):Send Receive操作

我們剛剛舉例說明的是一個RDMA Send操作。在IB或RoCE中,傳送一個小緩沖區裡的資料耗費的總時間大約在1.3µs。通過同時建立很多WQE, 就能在1秒内傳輸存放在數百萬個緩沖區裡的資料。

4. 總結

在這部落格中,我們學習了如何使用RDMA verbs API。同時也介紹了隊列的概念,而隊列概念是RDMA程式設計的基礎。最後,我們示範了RDMA send操作,展現了緩沖區的資料是如何在從一個系統搬運到另一個系統上去的。

下一章

《RDMA技術詳解(一):RDMA概述》【RDMA】技術詳解(一):RDMA概述_bandaoyu的筆記-CSDN部落格