RDMA在典型場景下的技術應用分析與探索

本文首發于:RDMA在典型場景下的技術應用分析與探索

?

1.業務適配RDMA類型

RDMA傳輸的適配,從業務場景的使用角度來看,大致可分為如下幾種類型。

場景一:機器學習、分布式存儲等場景,使用社區成熟的方案,如在機器學習場景中使用的NCCL、Tensorflow等框架中都適配了多種傳輸方式(包含tcp、rdma等),塊存儲Ceph中也同時支持tcp及rdma兩種通信模式,這種業務場景下業務側更多關注的是配置及使用,在IAAS基礎設施側將RDMA環境準備好后,使能框架使用rdma的傳輸模式即可。

場景二:業務程序使用類似于RPC遠程調用的通信方式,業務側需要將原有使用的RPC(大部分是GRPC)調用改為ORPC調用,在這種場景下業務和傳輸更像是兩個獨立的模塊,通過SDK的方式進行調用,所以適配起來改造的代碼并不多,通常是業務層面修改調用RPC的接口方式。但由于業務方可能使用多種編程語言,RPC over RDMA需要進行編程語言進行適配。

場景三:業務程序通信是私有化通信,比如使用socket套接字結合epoll完全自有實現的一套通信機制。這種場景下其實改造也區分情況,即業務IO與網絡IO是否耦合,若比較解耦,代碼中抽象出一層類似于最新Redis代碼中ConnectionType這樣的架構[2],那么只需要實現一套基于RDMA通信且符合Redis ConnectionType接口定義的新傳輸類型即可,改造量相對可控并且架構上也比較穩定;而若業務IO與網絡IO結合的較為緊密的情況下,這種場景下往往改造起來會比較復雜,改造的時候需要抽絲剝繭的找出業務與網絡之間的邊界,再進行網絡部分的改造。

2.Redis RDMA改造方案分析

首先,以Redis改造為RDMA傳輸為例,分析基于RDMA傳輸的應用程序改造邏輯與流程。

第一步是需要梳理出來Redis中與網絡傳輸相關的邏輯,這部分有比較多的參考資料,這里簡單總結一下。

Redis中實現了一套Reactor模式的事件處理邏輯名為AE,其主要流程為:

1、使用epoll等機制監聽各文件句柄,包括新建連接、以及已建立的連接等;

2、根據事件的不同調用對應的事件回調處理;

3、循環進行epoll loop并進行處理。

參考[2]中分析了當前redis的連接管理是圍繞connection這個對象進行管理(可類比socket套接字的管理),抽象一層高于socket的connection layer,以便兼容不同的傳輸層,各個字段解釋如下。

type:各種連接類型的回調接口,定義了諸如事件回調、listen、accept、read、write等接口,類比tcp socket實現的proto_ops。

state:當前連接的狀態,如CONNECTING/ACCEPTING/CONNECTED/CLOSED等狀態,類比TCP的狀態管理。

fd:連接對應的文件句柄。

iovcnt:進行iov操作的最大值。

private_data:保存私有數據,當前存放的是redis中client的指針。

conn_handler/write_handler/read_handler:分別對應連接connect、write、read時的處理接口。

get_type: connection的連接類型,當前redis已支持tcp、unix、tls類型,返回字符串。

init:在每種網絡連接模塊注冊時調用,各模塊私有初始化,如tcp、unix類型當前未實現,tls注冊時做了一些ssl初始化的前置工作。

ae_handler: redis中的網絡事件處理回調函數,redis中使用aeCreateFileEvent為某個fd及事件注冊處理函數為ae_handler,當redis的主循環aeMain中發現有響應的事件時會調用ae_handler進行處理,如在tcp連接類型中ae_handler為connSocketEventHandler,該函數分別處理了鏈接建立、鏈接可讀、鏈接可寫三種事件。

listen: 監聽于某個IP地址和端口,在tcp連接類型中對應的函數為connSocketListen,該函數主要調用bind、listen。

accept_handler: redis作為一個服務端,當接收到客戶端新建連接的請求時候的處理函數,一般會被.accept函數調用,比如在tcp連接類型中,connSocketAccept調用accept_handler,該方法被注冊為connSocketAcceptHandler,主要是使用accept函數接收客戶端請求,并調用acceptCommonHandler創建client。

addr: 返回連接的地址信息,主要用于一些連接信息的debug日志。

is_local:返回連接是否為本地連接,redis在protected模式下時,調用該接口判斷是否為本地連接進行校驗。

conn_create/conn_create_accepted:創建connection,對于tcp連接類型,主要是申請connection的內存,以及connection初始化工作。

shutdown/close:釋放connection的資源,關閉連接,當某個redis客戶端移除時調用。

connect/blocking_connect:實現connection的非阻塞和阻塞連接方法,在tcp連接類型中,非阻塞連接調用aeCreateFileEvent注冊連接的可寫事件,繼而由后續的ae_handler進行處理,實現非阻塞的連接;而阻塞連接則在實現時會等待連接建立完成。

accept:該方法在redis源碼中有明確的定義,可直接調用上述accept_handler,tcp連接類型中,該方法被注冊為connScoketAccept。

write/writev/read:和linux下系統調用write、writev、read行為一致,將數據發送至connection中,或者從connection中讀取數據至相應緩沖區。

set_write_handler:注冊一個寫處理函數,tcp連接類型中,該方法會注冊connection可寫事件,回調函數為tcp的ae_handler。

set_read_handler:注冊一個讀處理函數,tcp連接類型中,該方法會注冊connection可讀事件,回調函數為tcp的ae_handler。

sync_write/sync_read/sync_readline:同步讀寫接口,在tcp連接類型中實現邏輯是使用循環讀寫。

has_pending_data:檢查connection中是否有尚未處理的數據,tcp連接類型中該方法未實現,tls連接類型中該方法被注冊為tlsHasPendingData,tls在處理connection讀事件時,會調用SSL_read讀取數據,但無法保證數據已經讀取完成[3],所以在tlsHasPendingData函數中使用SSL_pending檢查緩沖區是否有未處理數據,若有的話則交由下面的process_pending_data進行處理。has_pending_data方法主要在事件主循環beforesleep中調用,當有pending data時,事件主循環時不進行wait,以便快速進行下一次的循環處理。

process_pending_data:處理檢查connection中是否有尚未處理的數據,tcp連接類型中該方法未實現,tls連接類型中該方法被注冊為tlsProcessPendingData,主要是對ssl緩沖區里面的數據進行讀取。process_pending_data方法主要在事件主循環beforesleep中調用

get_peer_cert:TLS連接特殊方法。

結合當前代碼中tcp及tls實現方法,梳理出和redis connection網絡傳輸相關的流程:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖:Redis Connection Call Graph


對于redis來說新增一個RDMA方式的傳輸方式,即是要將connection中的各種方法按照上述定義去使用RDMA編程接口去實現。RDMA編程一般采用CM管理連接加Verbs數據收發的模式,客戶端與服務端的交互邏輯大致如下圖所示,參考[16]。

?字節跳動的pizhenwei同學目前在redis社區中已經提交了redis over rdma的PR,參見[4],具體的代碼均在rdma.c這一個文件中。由于RDMA在做遠程內存訪問時,需要使用對端的內存地址,所以作者實現了一套RDMA客戶端與服務端的交互機制,用于通告對端進行遠程內存寫入的內存地址,參見[5]。

交互邏輯及說明如下:

1、增加了RedisRdmaCmd,用于Redis客戶端與服務端的控制面交互,如特性交換、Keepalive、內存地址交換等;

2、在客戶端及服務端建立完成RDMA連接后,需要先進行控制面的交互,當內存地址交換完成后,方可以進行Redis實際數據的交互及處理;

3、控制面消息通過IBV_WR_SEND方式發送,Redis數據交互通過IBV_WR_RDMA_WRITE_WITH_IMM發送,通過方法的不同來區分是控制面消息還是Redis的實際數據;

4、客戶端及服務端共享了一片內存,則需要對內存的使用管理,目前有三個變量用戶協同讀寫雙方的內存使用。

  • tx.offset為RDMA發送側已經對內存寫入的偏移地址,從發送端角度看內存已經使用到了tx.offset位置,下次發送端再進行RDMA寫入時,內存地址只能為tx.offset + 1;
  • rx.offset為RDMA接收側已經收到的內存偏移地址,雖然數據可能實際上已經到了tx.offset的位置,但由于接收側需要去處理CQ的事件,才能獲取到當前數據的位置,rx.offset是通過IMM中的立即數進行傳遞的,發送側每次寫入數據時,會將數據長度,所以rx.offset <= tx.offset;
  • rx.pos 為接收方上層業務內存的偏移地址,rx.pos <= rx.offset。

5、當rx.pos等于memory.len時,說明接收側內存已滿,通過內存地址交換這個RedisRdmaCmd進行控制面交互,將tx.offset、rx.offset、rx.pos同時置零,重新對這片共享內存協同讀寫。

Connection各方法的主要實現邏輯及分析如下:

listen:主要涉及RDMA編程圖示中listen、bind的流程,結合redis的.init相關調用流程,會將cm_channel中的fd返回給網絡框架AE,當后續客戶端連接該fd時,由AE進行事件回調,即后續的accepHandler。

accept_handler:該函數作為上述listen fd的事件回調函數,會處理客戶端的連接事件,主要調用.accept方法進行接收請求,并使用acceptCommonHandler調用后續的.set_read_handler注冊已連接的讀事件,參見圖Redis Connection Call Graph。

accept:要涉及RDMA編程圖示中accept的流程,處理RDMA_CM_EVENT_CONNECT_REQUEST、RDMA_CM_EVENT_ESTABLISHED等cm event,并進行cm event的ack。

set_read_handler:設置連接可讀事件的回調為.ae_handler。

read_handler:實際處理中會被設置為readQueryFromClient。

read:從本地緩沖區中讀取數據,該數據是客戶端通過遠程DMA能力寫入。

set_write_handler:將write_handler設置為回調處理函數,這里和tcp、tls實現的方式有所區別,并沒有注冊connection的可寫事件回調,是因為RDMA中不會觸發POLLOUT(可寫)事件,connection的寫由ae_handler實現。

write_handler:實際工作中被設置為sendReplyToClient。

write:將Redis的數據拷貝到RMDA的本地緩沖區中,通過ibv_post_send,這部分數據會通過遠程DMA能力寫入對端。

has_pending_data:檢查內部的pending_list,在收到RDMA_CM_EVENT_DISCONNECTED等事件時,會將當前connection加入到pending_list中,由后續beforeSleep時調用process_pending_data進行處理。

process_pending_data:檢查pending的connection,并調用read_handler讀取connection中的數據。

ae_handler:該方法有三個處理流程,第一是處理RDMA CQ事件,包括接收處理RedisRdmaCmd控制面消息,接收RDMA IMM類事件增加rx.offset;第二是調用read_handler和write_handler,這部分是與tcp、tls流程一致;第三是檢查rx.pos和rx.offset的值,若rx.pos == memory.len時,發送內存地址交換這個RedisRdmaCmd控制面消息。

3.Redis RDMA測試

Redis測試通常采取自帶的redis-benchmark工具進行測試,該工具復用了redis中的ae處理邏輯,并調用hiredis進行redis數據的解析,在參考[6]中fork并改造了一份基于RDMA的redis-benchmark,可直接編譯使用,接下來使用該工具進行tcp及RDMA方式的性能測試對比。

在實際測試中使用的是同一個交換機下的兩臺服務器,傳輸方式是rocev2,經過qperf的測試,tcp的latency為12us,rocev2的latency為4us。

3.1 單并發單線程

TCP方式

RedisServer:./src/redis-server --protected-mode no

RedisBenchmark:./src/redis-benchmark -h xx.xx.xx.xx -p 6379 -c 1 -n 500000 -t get

RDMA方式

RedisServer:./src/redis-server --loadmodule src/redis-rdma.so port=6379 ?bind=xx.xx.xx.xx --protected-mode no

RedisBenchmark:./src/redis-benchmark -h xx.xx.xx.xx -p 6379 -c 1 -n 500000 -t get --rdma

3.2 多并發多線程

Redisbenchmark單線程4連接:

Redisbenchmark單線程8連接:

?Redisbenchmark單線程16/32連接:

?注:在我們的測試環境中16個連接時,redis-benchmark已經100%,再進行增加連接數測試時,qps也不會再增加。

Redisbenchmark 4線程4連接:

Redisbenchmark 4線程16連接:

Redisbenchmark 4線程32/64連接:

注:在我們的測試環境中4線程32連接時,redis-server已經100%,再進行增加連接數測試時,qps也不會再增加。

更多的連接和線程:

3.3 測試總結

  • 整體而言,在我們的測試環境下,redis服務能力rocev2(rdma)的傳輸方式相較tcp,有~50% 到 ~100%左右的能力提升。
  • 可以發現,由于rdma bypass了內核協議棧,相同物理拓撲下redis一次讀取時延下降了16us左右(見3.1單并發測試數據),這里額外做了一個測試,選取了另外一組相隔較遠的機器進行測試,發現讀取時延仍然縮小的是這個數量級,見下圖。

  • rdma方式建鏈的時間較長,實際測試中連接數越多,redis-benchmark真正開始測試的時間越長。

4.開源程序基于RDMA方案

4.1 Tensorflow RDMA

Tensorflow是一個廣泛使用的深度學習框架,在Tensorflow中數據通常表示為Tensor張量,Tensor是一個多為數據,可以在不同的設備之間進行傳輸,以便進行分布式計算。

在分布式系統中,Tensorflow可以通過網絡傳輸將Tensor從一個節點傳輸到另一個節點,從1.1版本開始支持RDMA傳輸,以下為其基于RDMA傳輸的主要方案,參考[7] [8]。

  • 在RDMA傳輸通道建立之前,使用基于tcp的grpc通道傳輸傳遞RDMA的內存地址、MR key、服務地址等信息
  • 內存拷貝方案:

a)對于可以DMA的Tensor(包括CPU上的內存或者GPU Direct的內存),采用直接從源Tensor寫到目標Tensor中的方案,實現內存零拷貝

b)對于非DMA得Tensor,用protobuf序列化后,通過RDMA方式寫到接收端預先注冊的內存中

c)對于不支持GPU Direct的Tensor,通過RDMA方式寫到接收端的CPU內存,再在接收端通過拷貝的方式到GPU中,發送與接收CPU之間不存在內存拷貝

  • 內部使用RdmaBuffer用于RDMA讀寫的內存單元,RdmaBuffer有三個派生類,分別是RdmaAckBuffer、RdmaMessageBuffer和RdmaTensorBuffer,RdmaMessageBuffer負責發送 message ,比如請求一個tensor等等。一旦一個message被發送,message的接收方需要通過RdmaAckBuffer發送一個ack來釋放發送方的message buffer。一個RdmaAckBuffer和唯一的RdmaMessageBuffer綁定。RdmaTensorBuffer負責發送tensor,tensor的接收方需要返回一個message來釋放發送方的buffer
  • 對于一個具體的recv和send流程如下:

a)接收側發送RDMA_MESSAGE_TENSOR_REQUEST消息,其中包含目的Tensor的地址,以用于發送側進行RDMA寫入。

b)為避免在每個步驟中發送額外的元數據消息,為每個Tensor維護一個本地元數據緩存,僅在更改時才會更新,每個RDMA_MESSAGE_TENSOR_REQUEST將包含接收方從本地緩存中獲取的元數據。發送方將比較消息中的元數據和Tensor的新元數據,如果元數據更改,發送側發送包含新元數據的RDMA_MESSAGE_META_DATA_RESPONSE。

c)當接收方收到 RDMA_MESSAGE_META_DATA_RESPONSE 時,將更新本地元數據緩存,重新分配結果/代理Tensor,重新發送Tensor請求。為了可追溯性,新的消息具有不同的名稱RDMA_MESSAGE_TENSOR_RE_REQUEST。

d)當發送方收到 RDMA_MESSAGE_TENSOR_RE_REQUEST 時,它將使用消息中指定的請求索引定位相關的 RdmaTensorResponse,并調用其 Resume方法,該方法將 RDMA 寫入之前克隆的Tensor的內容,到重新請求中指定的新遠程地址。

e)當接收方接收到 RDMA 寫入時,它將使用立即值作為請求索引,找到相關的 RdmaTensorRequest,然后調用其 RecvTensorContent方法,包含可能存在的內存復制、反序列化等工作。

4.2 Brpc RDMA

百度的brpc當前的RDMA傳輸實現中,數據傳輸是使用RMDA_SEND_WITH_IMM進行操作,這就要求接收端在接收數據前要先準備好內存并預先POST RECV。為了實現高效的內存管理,brpc內部實現了靜態內存池,且在RDMA數據傳輸實現中做了如下幾點優化,參考[9][10]。

  • 數據傳輸零拷貝,要發送的所有數據默認都存放在IOBuf的Block中,因此所發送的Block需要等到對端確認接收完成后才可以釋放,這些Block的引用被存放于RdmaEndpoint::_sbuf中。而要實現接收零拷貝,則需要確保接受端所預提交的接收緩沖區必須直接在IOBuf的Block里面,被存放于RdmaEndpoint::_rbuf。注意,接收端預提交的每一段Block,有一個固定的大小(recv_block_size)。發送端發送時,一個請求最多只能有這么大,否則接收端則無法成功接收。
  • 數據傳輸有滑動窗口流控,這一流控機制是為了避免發送端持續在發送,其速度超過了接收端處理的速度。TCP傳輸中也有類似的邏輯,但是是由內核協議棧來實現的,brpc內實現了這一流控機制,通過接收端顯式回復ACK來確認接收端處理完畢。為了減少ACK本身的開銷,讓ACK以立即數形式返回,可以被附在數據消息里。
  • 數據傳輸邏輯的第三個重要特性是事件聚合。每個消息的大小被限定在一個recv_block_size,默認為8KB。如果每個消息都觸發事件進行處理,會導致性能退化嚴重,甚至不如TCP傳輸(TCP擁有GSO、GRO等諸多優化)。因此,brpc綜合考慮數據大小、窗口與ACK的情況,對每個發送消息選擇性設置solicited標志,來控制是否在發送端觸發事件通知。

4.3 NCCL RDMA

NCCL的網絡傳輸實現是插件式的,各種不同的網絡傳輸只需要按照ncclNet中定義的方法去具體實現即可。

其中最主要的是isend、irecv及test方法,在調用 isend 或 irecv 之前,NCCL 將在所有緩沖區上調用 regMr 函數,以便 RDMA NIC 準備緩沖區,deregMr 將用于注銷緩沖區。

以下是NCCL RDMA的實現部分邏輯,基于當前NCCL最新版本GitHub - NVIDIA/nccl at v2.18.3-1分析,主要參考[11]及參考[12](當前實現與參考中略有不同).

  • 在NCCL基于RDMA的傳輸實現中,目前的數據傳輸主要是通過RDMA_WRITE操作
  • 由于發送端進行RDMA_WRITE時,需要預先知道對端的DMA地址,NCCL中發送/接收端是通過一個緩沖區ncclIbSendFifo進行交互
  • ncclIbSendFifo是發送端申請的一塊內存緩沖區,在connect與accept階段通過傳統tcp socket的方式攜帶給接收端
  • 在接收端異步進行接收時,recvProxyProgress調用irecv接口進行接收,在RDMA的實現中對應的是將本端DMA的地址通過ncclIbSendFifo RDMA_WRITE至發送端
  • 發送端進行發送時,sendProxyProgress調用isend接口進行發送,在RDMA中對應的是從ncclIbSendFifo中獲取接收端的DMA地址,將上層的data直接RDMA_WRITE至接收端的DMA地址中

  • 接收端維護本地的remFifoTail游標,每次接收時游標后移一位,接收端會將idx設置為一個自增的索引,同時將上層的DMA地址通過ncclIbSendFifo攜帶給發送端
  • 發送端維護本地的fifoHead游標,每次發送后游標后移一位,發送端檢查fifo中元素的idx值是否為預期索引來判斷該fifo是否已經被接收端設置過,即接收端的DMA地址已經可以寫入

struct ncclIbSendFifo {

? uint64_t addr;

? int? ? ? size;

? uint32_t rkey;

? uint32_t nreqs;

? uint32_t tag;

? uint64_t idx;

};

// 發送端

ncclIbIsend:

uint64_t idx = comm->fifoHead+1;

if (slots[0].idx != idx) { *request = NULL; return ncclSuccess; }

comm->fifoHead++;

//接收端

ncclIbIrecv -> ncclIbPostFifo :

localElem[i].idx = comm->remFifo.fifoTail+1;

comm->remFifo.fifoTail++;

4.4 Libvma及SMC-R方式

除了上述修改業務源碼的方案,業內也有“零入侵”業務程序的方案,比如libvma及smc-r方式。

SMC-R:

smc-r(SMC over RDMA)是IBM在2017提交至linux kernel的一種兼容socket層,使用共享內存技術、基于RDMA技術實現的高性能內核網絡協議棧。smc-r的主要實現是在內核態實現了一個新的af_smc協議族,基于RDMA verbs接口實現內核proto_ops中的各方法。

smc-r支持fallback回退機制,在通信雙方最開始建立連接時是使用tcp握手(特定的tcp選項)進行協商是否雙方均支持SMC-R能力,當協商不成功時fallback為原始的tcp通信。完成協議協商并建立連接后,協議棧為SMC-R socket分配一塊用于緩存待發送數據的環形緩沖區sndbuf和一塊用于緩存待接收數據的環形緩沖區RMB(Remote Memory Buffer)。

  • 發送端應用程序通過socket接口將待發送數據拷貝到本側sndbuf中,由SMC-R協議棧通過RDMA WRITE操作直接高效地寫入對側節點的RMB中。同時伴隨著使用RDMA SEND/RECV操作交互連接數據管理消息,用于更新、同步環形緩沖區中的數據游標。
  • 接收端SMC-R協議棧感知到RMB中填入新數據后,通過epoll等方式告知接收端應用程序將RMB中的數據拷貝到用戶態,完成數據傳輸。所以在SMC-R中,RMB充當傳輸過程中的共享內存。

?下面是一個基于smc-r通信的實際測試場景的協商交互抓包:

Libvma:

Libvma是Mellanox公司開源的一款高性能的用戶態網絡協議棧,它將socket的相關接口全部在用戶態空間實現,實現對內核的旁路,使用RDMA verbs接口直接調用網卡驅動,從而節省了大量的上下文數據拷貝,節省了 CPU 的資源降低了時延,業務在使用libvma時只需要使用LD_PRELOAD libvma.so替換原有的系統調用即可完成傳輸協議的替換。

Libvma內部在tcp協議棧的實現上使用了lwip方案,重寫了epoll,使用了hugepage,內部使用單獨的線程去輪詢RDMA CQ事件等方案,相較于內核協議棧的實現,在主機側的處理延遲有200%至500%的降低。

此外,在實際測試過程中發現libvma雖然使用的是RDMA verbs接口,但實際針對Mellanox mlx5系列驅動的網卡是直接用戶態驅動網卡,發送的仍然是原始基于tcp的以太報文,并不是rocev2的報文,具體討論可以見github上的issue參考[15]。

下面是基于libvma測試redis的場景,由于libvma bypass協議棧,并且重寫了epoll等其它特性,性能提升大概3倍:

總結:

相較于業務使用raw verbs進行源碼修改,libvma及smc-r方式可以提供“零入侵、零修改”源碼的優勢,但由于應用程序在將數據提供給socket接口時仍然存在一次拷貝,所以性能上對比verbs方案來說有一定的損耗,對于想快速驗證RDMA能力的業務是一個不錯的POC驗證方式。

目前阿里云的Alibaba Cloud Linux3默認支持smc-r能力,結合阿里云的eRDMA能力網卡,可以使業務進行透明無損的RDMA傳輸替換,減少cpu的使用率,降低一定的通信延時。但目前該能力在阿里云上屬于公測能力,生產穩定性待驗證,參考[14]。

libvma方式沒有linux社區的支持,并且更多的是針對Mellanox系列網卡的支持,在工業界使用的場景也不太多,目前在金融的高頻交易領域有一些使用嘗試。

5.總結與展望

前面主要分析和調研了一些開源應用在進行業務適配RDMA傳輸的方案,整體來看RDMA改造的方案是分為兩部分,分別為通信接口的改造以及RDMA內存管理設計。

通信接口改造主要指將tcp socket的傳輸接口修改為ib verbs或者cm接口,這部分同時涉及到適配現有業務網絡事件的處理模型。

由于RDMA傳輸數據時,需要預先將內存注冊到HCA卡上,所以RDMA內存管理會比較復雜,同時也是性能高低與否的關鍵。

1)數據傳輸時申請內存,并進行內存注冊,再進行RDMA操作。顯然這種模式在代碼實現上最為簡單,但是性能及效率最低,現有方案中很少有在fast path中使用這種內存管理方案。

2)提前注冊好一大塊內存,在上層業務需要發送數據時,將數據拷貝至RDMA注冊好的內存。這種模式性能相較第一種有提升,但存在一定的內存拷貝。

3)使用內存池,業務及RDMA的內存使用同一塊。性能明顯是最優的,但是實現邏輯較復雜,需要管理好內存的申請及釋放、某些實現中通信雙方也需要做內存使用量的協商。

結合前面應用的RDMA方案,匯總如下表:

應用名稱

網絡處理模型

內存方案

其它特性

Redis (pr stage)

1.適配原有的單線程reactor非阻塞模式

2.rdma無pollout時間,在業務邏輯中額外處理

3.網絡支持插件式,不同的傳輸模式實現相同的網絡方法

1.預注冊內存,RDMA Write模式

2.DMA地址通過控制消息交互

3.應用與RDMA之間存在拷貝

1.有控制面交互,如xferbuffer

2.控制面信息復用RDMA通道

Tensorflow

異步發送、阻塞接收

1.RDMA Write模式

2.應用及RDMA共享內存池

3.通信雙方通過消息交互DMA地址

1.使用基于TCP的GRPC通道進行RDMA鏈接的協商

2.有控制面消息交互,如metadata更新

3.控制面信息復用RDMA通道

BRPC

reactor模式

1.內存池模式

2.使用RDMA Send模式

1.額外的流控機制

2.事件聚合

NCCL

1.reactor模式

2.網絡支持插件式,不同的傳輸模式實現相同的網絡方法

1.RDMA Write模式

2.通信雙方通過一個共享fifo來交互具體的DMA地址

3.DMA地址是預先注冊的內存

1.RDMA建立階段使用TCP鏈接進行協商

隨著AI的火熱,國產DPU、GPU的高速發展,數據中心內在高性能計算、機器學習、分布式存儲等場景下的業務也需要隨著硬件能力的提升去適配使用這些能力,RDMA因其諸多優點目前已經廣泛被應用。調研學習現有的方案是為了更好地適配及修改自研的業務,相信隨著越來越多業務場景下RDMA的使用,其相關生態及應用方案也會越來越成熟。

內容基于網上資料及源碼分析整理,歡迎討論及批評指正。

參考

[1]orpc 基于RDMA的云服務能力實踐與探索

[2]redis網絡連接層 Redis網絡連接層的過去、現狀和展望-騰訊云開發者社區-騰訊云

[3]openssl pending:ssl的消息讀寫以及和tcp語義的異同_weixin_33816300的博客-CSDN博客

[4]redis over rdma : GitHub - pizhenwei/redis at feature-rdma

[5]redis over rdma protocol: https://github.com/pizhenwei/redis/blob/feature-rdma/RDMA.md

[6]redis over rdma test: forsakening/rdma-redis-test · GitHub

[7]tensorflow over rdma https://github.com/tensorflow/networking/blob/master/tensorflow_networking/verbs/README.md

[8]tensorflow rdma源碼剖析 https://github.com/chenpai/TensorFlow-RDMA/blob/master/TensorFlow%20RDMA%20%E6%BA%90%E7%A0%81%E5%89%96%E6%9E%90.md

[9]brpc的rdma特性 https://github.com/apache/brpc/blob/master/docs/cn/rdma.md

[10]brpc的rdma實現 brpc源碼學習(十)- RDMA通信_brpc rdma_KIDGINBROOK的博客-CSDN博客

[11]nccl多機通信流程 NVIDIA NCCL 源碼學習(十)- 多機間ncclSend和ncclRecv的過程_KIDGINBROOK的博客-CSDN博客

[12]nccl net plugin https://github.com/NVIDIA/nccl/blob/master/ext-net/README.md

[13]libvma GitHub - Mellanox/libvma: Linux user space library for network socket acceleration based on RDMA compatible network adaptors

[14]阿里云smc-r SMC-R是什么,使用方法有哪些_云服務器 ECS-阿里云幫助中心

[15]libvma packet type issue NOT see any rocev2 packet · Issue #1036 · Mellanox/libvma · GitHub

[16]RDMA CM交互流程 IBM Documentation

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/38209.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/38209.shtml
英文地址,請注明出處:http://en.pswp.cn/news/38209.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

c++小技巧13:中文輸出(編碼轉漢字)

目錄 1.前言 2.正文 1.直接輸出: 2.間接輸出 3.編碼(?)轉漢字&#xff08;建議直接看這個&#xff09; (書簽) 3.后文 1.前言 &#xff08;os:感覺標題中 間接不太準確&#xff0c;主要是找不到精準的用詞&#xff0c;說明一下&#xff1a;就是在不用中文的方式下輸出…

ibmtpm-TPMCmd 編譯

HASH_LIBOssl SYM_LIBOssl MATH_LIBOssl tpm工程: platform.lib libeay32.lib Windows 編譯 openssl-1.0.2p&#xff08;libeay32.lib、ssleay32.lib&#xff09;靜態庫 32/64、debug/release、MT/MTd D:\installed\mingw64\opt\bin\libeay32.dll

使用Mix-in類組合功能

為什么需要Mix-in? 在學習面向對象時我們知道&#xff0c;類可以通過繼承類獲得屬性和方法&#xff0c;通過繼承可以減少重復代碼、提高復用率。Python支持多繼承&#xff0c;一個類可以通過繼承多個類來得到它們的功能。但多繼承會帶來一些問題&#xff0c;比如屬性沖突。那…

鏈表之第一回

歡迎來到我的&#xff1a;世界 收錄專欄&#xff1a;鏈表 希望作者的文章對你有所幫助&#xff0c;有不足的地方還請指正&#xff0c;大家一起學習交流 ! 目錄 前言第一題&#xff1a;刪除鏈表的倒數第n個節點第二題&#xff1a;鏈表的中間結點第三題&#xff1a;合并兩個排序…

如何在 iOS 上安裝并使用 ONLYOFFICE 文檔

借助 iOS 版文檔應用&#xff0c;您可在移動端設備上訪問存儲于 ONLYOFFICE 賬戶中的文件&#xff0c;查看和編輯現有文本文檔、電子表格和演示文稿&#xff0c;創建新文檔并對其進行整理&#xff0c;以及連接第三方云存儲服務。您可與其他門戶網站用戶協作編輯文檔&#xff0c…

數據結構-棧和隊列

目錄 棧的概念 棧的使用 ?編輯 模擬實現棧 中綴表達式轉后綴表達式 括號匹配 出棧入棧次序匹配 隊列概念 隊列的使用 棧的概念 棧是一種特殊的線性表,其只允許在固定的一端進行插入和刪除元素的操作.進行數據插入和刪除操作的一端稱為棧頂,;另一端稱為棧底.棧中的數據…

【Vue-Router】嵌套路由

footer.vue <template><div><router-view></router-view><hr><h1>我是父路由</h1><div><router-link to"/user">Login</router-link><router-link to"/user/reg" style"margin-left…

面試攻略,Java 基礎面試 100 問(十五)

final, finally, finalize 的區別? final&#xff1a;修飾符&#xff08;關鍵字&#xff09;有三種用法&#xff1a;如果一個類被聲明為 final&#xff0c;意味著它不能再派生出新的子類&#xff0c;即不能被繼承&#xff0c;因此它和 abstract 是反義詞。將變量聲明為 final…

動手學DL——MLP多層感知機【深度學習】【PyTorch】

文章目錄 4、多層感知機&#xff08; MLP&#xff09;4.1、多層感知機4.1.1、隱層4.1.2、激活函數 σ 4.2、從零實現多層感知機4.3、簡單實現多層感知機4.4、模型選擇、欠擬合、過擬合4.5、權重衰退4.6、丟失法|暫退法&#xff08;Dropout&#xff09;4.6.1、dropout 函數實現4…

大數據--難點--地圖的制作

地圖一直是亮點也是難點&#xff0c;剛剛進公司的時候也很難懂~~做出來的也很難看 純CSS3使用vw和vh視口單位實現h5頁面自適應&#xff0c;gulp自動監聽sass改動并保存到css中 當修改了sass里面的代碼后&#xff0c;gulp會自動監聽修改內容并同名保存到css文件夾中&#xff0…

C#字符串占位符替換

using System;namespace myprog {class test{static void Main(string[] args){string str1 string.Format("{0}今年{1}歲&#xff0c;身高{2}cm&#xff0c;月收入{3}元&#xff1b;", "小李", 23, 177, 5000);Console.WriteLine(str1);Console.ReadKey(…

02-C++數據類型-高級

數據類型-高級 4、復合類型 4.4、結構簡介 struct inflatable {char name[20];float vol;double price; };inflatable vincent; //C struct inflatable goose; //C例子 // structur.cpp -- a simple structure #include <iostream> struct inflatable // structu…

B057-spring增強 依賴注入 AOP 代理模式 創建Bean

目錄 AOP概念代理模式引出AOP實現方式xml方式實現注解方式實現 AOP 概念 事務管理&#xff1a;比如可以抽取try catch的重復代碼 日志監控&#xff1a;比如業務邏輯前后打印關于當前訂單數量的日志&#xff0c;了解業務做了什么 性能監控&#xff1a;比如業務前后打印時間&…

浪潮信息趙帥:多元算力時代 開源開放的OpenBMC成為服務器管理優先解

“多元算力時代下&#xff0c;大規模的異構服務器設備面臨多種處理器架構、多種設備協議、不同管理芯片兼容的系統化設計挑戰&#xff0c;管理固件也迎來新的變革。開源開放的OpenBMC&#xff0c;以創新的分層解耦軟件架構&#xff0c;兼容不同處理器架構、算力平臺和管理芯片&…

人流目標跟蹤pyqt界面_v5_deepsort

直接上效果圖 代碼倉庫和視頻演示b站視頻006期&#xff1a; 到此一游7758258的個人空間-到此一游7758258個人主頁-嗶哩嗶哩視頻 代碼展示&#xff1a; YOLOv5 DeepSORT介紹 YOLOv5 DeepSORT是一個結合了YOLOv5和DeepSORT算法的目標檢測與多目標跟蹤系統。讓我為您詳細解釋一…

【字典學習+稀疏編碼Sparse Encoding】簡單介紹與sklearn的實現方式

文章目錄 1、字典學習與稀疏編碼2、sklearn的實現3、示例 1、字典學習與稀疏編碼 簡單來說&#xff0c;稀疏編碼就是把輸入向量&#xff08;信號&#xff09;/ 矩陣&#xff08;圖像&#xff09;表示為稀疏的系數向量和一組超完備基向量&#xff08;字典&#xff09;的線性組合…

vim打開文件中文是亂碼

vim打開文件中文是亂碼 問題&#xff1a;在Linux系統下&#xff0c;使用cat查看含有中文的文本文件正常&#xff0c;但是使用vim打開卻是亂碼 解決方法&#xff1a; 方法一&#xff1a; 在文件中設定 在vim的退出模式下 :set encodingutf8 方法二&#xff1a; 直接寫入/etc/…

ASP.NET WEB API通過SugarSql連接MySQL數據庫

注意&#xff1a;VS2022企業版可以&#xff0c;社區版可能存在問題。實體名稱和字段和數據庫中的要一致。 1、創建項目&#xff0c;安裝SqlSugarCore、Pomelo.EntityFrameworkCore.MySql插件 2、文件結構 2、appsettings.json { “Logging”: { “LogLevel”: { “Default”: …

Ubuntu 軟件依賴出錯處理

現象&#xff1a; apt-get install vim 正在讀取軟件包列表... 完成 正在分析軟件包的依賴關系樹 正在讀取狀態信息... 完成 您可能需要運行“apt-get -f install”來糾正下列錯誤&#xff1a; 下列軟件包有未滿足的依賴關系&#xff1a; cuttlefish-base : 依賴: f2fs-tools…

DG故障切換及DG Broker失效配置清理

DG故障切換及DG Broker失效配置清理 DG故障強制切主DG Broker原有配置清理 DG故障強制切主 主庫發生故障無法在短時間內恢復時&#xff0c;需要執行主備切換。此時由于DG Broker無法連接到主庫&#xff0c;故不能通過Broker切換&#xff0c;只能手動在備庫進行切主。 --斷開備…