0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Redis RDMA改造方案分析

OSC開源社區(qū) ? 來源:安第斯智能云 ? 2023-08-16 10:22 ? 次閱讀

01

業(yè)務適配RDMA類型

RDMA傳輸?shù)倪m配,從業(yè)務場景的使用角度來看,大致可分為如下幾種類型。

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

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

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

02

Redis RDMA改造方案分析

首先,以Redis改造為RDMA傳輸為例,分析基于RDMA傳輸?shù)膽贸绦蚋脑爝壿嬇c流程。

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

07ec4c1e-3b5d-11ee-9e74-dac502259ad0.png

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

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

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

3、循環(huán)進行epoll loop并進行處理。

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

07f9c9a2-3b5d-11ee-9e74-dac502259ad0.png

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

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

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

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

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

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

0807dc5e-3b5d-11ee-9e74-dac502259ad0.png

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

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

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

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

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

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

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

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

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

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

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

write/writev/read:和linux下系統(tǒng)調用write、writev、read行為一致,將數(shù)據(jù)發(fā)送至connection中,或者從connection中讀取數(shù)據(jù)至相應緩沖區(qū)。

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

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

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

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

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

get_peer_cert:TLS連接特殊方法。

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

0859d518-3b5d-11ee-9e74-dac502259ad0.png

圖:Redis Connection Call Graph

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

08652d8c-3b5d-11ee-9e74-dac502259ad0.png

圖:RDMA C/S Workflow

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

08742d46-3b5d-11ee-9e74-dac502259ad0.png

交互邏輯及說明如下:

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

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

3、控制面消息通過IBV_WR_SEND方式發(fā)送,Redis數(shù)據(jù)交互通過IBV_WR_RDMA_WRITE_WITH_IMM發(fā)送,通過方法的不同來區(qū)分是控制面消息還是Redis的實際數(shù)據(jù);

08830122-3b5d-11ee-9e74-dac502259ad0.png

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

tx.offset為RDMA發(fā)送側已經對內存寫入的偏移地址,從發(fā)送端角度看內存已經使用到了tx.offset位置,下次發(fā)送端再進行RDMA寫入時,內存地址只能為tx.offset + 1;

rx.offset為RDMA接收側已經收到的內存偏移地址,雖然數(shù)據(jù)可能實際上已經到了tx.offset的位置,但由于接收側需要去處理CQ的事件,才能獲取到當前數(shù)據(jù)的位置,rx.offset是通過IMM中的立即數(shù)進行傳遞的,發(fā)送側每次寫入數(shù)據(jù)時,會將數(shù)據(jù)長度,所以rx.offset <= tx.offset;

rx.pos 為接收方上層業(yè)務內存的偏移地址,rx.pos <= rx.offset。

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

Connection各方法的主要實現(xiàn)邏輯及分析如下:

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

accept_handler:該函數(shù)作為上述listen fd的事件回調函數(shù),會處理客戶端的連接事件,主要調用.accept方法進行接收請求,并使用acceptCommonHandler調用后續(xù)的.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:從本地緩沖區(qū)中讀取數(shù)據(jù),該數(shù)據(jù)是客戶端通過遠程DMA能力寫入。

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

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

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

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

process_pending_data:檢查pending的connection,并調用read_handler讀取connection中的數(shù)據(jù)。

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

03

Redis RDMA測試

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

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

3.1 單并發(fā)單線程

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

089447d4-3b5d-11ee-9e74-dac502259ad0.png

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

089ec2a4-3b5d-11ee-9e74-dac502259ad0.png

3.2多并發(fā)多線程

Redisbenchmark單線程4連接:

08aca3ba-3b5d-11ee-9e74-dac502259ad0.png

Redisbenchmark單線程8連接:

08bd7d0c-3b5d-11ee-9e74-dac502259ad0.png

Redisbenchmark單線程16/32連接:

08d3b7b6-3b5d-11ee-9e74-dac502259ad0.png

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

Redisbenchmark 4線程4連接:

08d8a67c-3b5d-11ee-9e74-dac502259ad0.png

Redisbenchmark 4線程16連接:

08e12950-3b5d-11ee-9e74-dac502259ad0.png

Redisbenchmark 4線程32/64連接:

08f1bf86-3b5d-11ee-9e74-dac502259ad0.png

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

更多的連接和線程:

0905362e-3b5d-11ee-9e74-dac502259ad0.png

3.3測試總結

091cb132-3b5d-11ee-9e74-dac502259ad0.png

整體而言,在我們的測試環(huán)境下,redis服務能力rocev2(rdma)的傳輸方式相較tcp,有~50% 到 ~100%左右的能力提升。

可以發(fā)現(xiàn),由于rdma bypass了內核協(xié)議棧,相同物理拓撲下redis一次讀取時延下降了16us左右(見3.1單并發(fā)測試數(shù)據(jù)),這里額外做了一個測試,選取了另外一組相隔較遠的機器進行測試,發(fā)現(xiàn)讀取時延仍然縮小的是這個數(shù)量級,見下圖。

092ee21c-3b5d-11ee-9e74-dac502259ad0.png

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

04

開源程序基于RDMA方案

4.1Tensorflow RDMA

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

在分布式系統(tǒng)中,Tensorflow可以通過網絡傳輸將Tensor從一個節(jié)點傳輸?shù)搅硪粋€節(jié)點,從1.1版本開始支持RDMA傳輸,以下為其基于RDMA傳輸?shù)闹饕桨福瑓⒖糩7][8]。

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

內存拷貝方案:

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

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

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

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

對于一個具體的recv和send流程如下:

0940ca9a-3b5d-11ee-9e74-dac502259ad0.png

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

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

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

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

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

4.2BrpcRDMA

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

數(shù)據(jù)傳輸零拷貝,要發(fā)送的所有數(shù)據(jù)默認都存放在IOBuf的Block中,因此所發(fā)送的Block需要等到對端確認接收完成后才可以釋放,這些Block的引用被存放于RdmaEndpoint::_sbuf中。而要實現(xiàn)接收零拷貝,則需要確保接受端所預提交的接收緩沖區(qū)必須直接在IOBuf的Block里面,被存放于RdmaEndpoint::_rbuf。注意,接收端預提交的每一段Block,有一個固定的大?。╮ecv_block_size)。發(fā)送端發(fā)送時,一個請求最多只能有這么大,否則接收端則無法成功接收。

數(shù)據(jù)傳輸有滑動窗口流控,這一流控機制是為了避免發(fā)送端持續(xù)在發(fā)送,其速度超過了接收端處理的速度。TCP傳輸中也有類似的邏輯,但是是由內核協(xié)議棧來實現(xiàn)的,brpc內實現(xiàn)了這一流控機制,通過接收端顯式回復ACK來確認接收端處理完畢。為了減少ACK本身的開銷,讓ACK以立即數(shù)形式返回,可以被附在數(shù)據(jù)消息里。

數(shù)據(jù)傳輸邏輯的第三個重要特性是事件聚合。每個消息的大小被限定在一個recv_block_size,默認為8KB。如果每個消息都觸發(fā)事件進行處理,會導致性能退化嚴重,甚至不如TCP傳輸(TCP擁有GSO、GRO等諸多優(yōu)化)。因此,brpc綜合考慮數(shù)據(jù)大小、窗口與ACK的情況,對每個發(fā)送消息選擇性設置solicited標志,來控制是否在發(fā)送端觸發(fā)事件通知。

4.3NCCLRDMA

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

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

以下是NCCL RDMA的實現(xiàn)部分邏輯,基于當前NCCL最新版本分析,主要參考[11]及參考[12]

(當前實現(xiàn)與參考中略有不同)。

在NCCL基于RDMA的傳輸實現(xiàn)中,目前的數(shù)據(jù)傳輸主要是通過RDMA_WRITE操作

由于發(fā)送端進行RDMA_WRITE時,需要預先知道對端的DMA地址,NCCL中發(fā)送/接收端是通過一個緩沖區(qū)ncclIbSendFifo進行交互

ncclIbSendFifo是發(fā)送端申請的一塊內存緩沖區(qū),在connect與accept階段通過傳統(tǒng)tcp socket的方式攜帶給接收端

在接收端異步進行接收時,recvProxyProgress調用irecv接口進行接收,在RDMA的實現(xiàn)中對應的是將本端DMA的地址通過ncclIbSendFifo RDMA_WRITE至發(fā)送端

發(fā)送端進行發(fā)送時,sendProxyProgress調用isend接口進行發(fā)送,在RDMA中對應的是從ncclIbSendFifo中獲取接收端的DMA地址,將上層的data直接RDMA_WRITE至接收端的DMA地址中

095bb832-3b5d-11ee-9e74-dac502259ad0.png

接收端維護本地的remFifoTail游標,每次接收時游標后移一位,接收端會將idx設置為一個自增的索引,同時將上層的DMA地址通過ncclIbSendFifo攜帶給發(fā)送端

發(fā)送端維護本地的fifoHead游標,每次發(fā)送后游標后移一位,發(fā)送端檢查fifo中元素的idx值是否為預期索引來判斷該fifo是否已經被接收端設置過,即接收端的DMA地址已經可以寫入

struct ncclIbSendFifo {
  uint64_t addr;
  int      size;
  uint32_t rkey;
  uint32_t nreqs;
  uint32_t tag;
  uint64_t idx;
};


// 發(fā)送端
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.4Libvma及SMC-R方式

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

SMC-R:

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

0960c304-3b5d-11ee-9e74-dac502259ad0.png

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

發(fā)送端應用程序通過socket接口將待發(fā)送數(shù)據(jù)拷貝到本側sndbuf中,由SMC-R協(xié)議棧通過RDMA WRITE操作直接高效地寫入對側節(jié)點的RMB中。同時伴隨著使用RDMA SEND/RECV操作交互連接數(shù)據(jù)管理消息,用于更新、同步環(huán)形緩沖區(qū)中的數(shù)據(jù)游標。

接收端SMC-R協(xié)議棧感知到RMB中填入新數(shù)據(jù)后,通過epoll等方式告知接收端應用程序將RMB中的數(shù)據(jù)拷貝到用戶態(tài),完成數(shù)據(jù)傳輸。所以在SMC-R中,RMB充當傳輸過程中的共享內存。

096d4912-3b5d-11ee-9e74-dac502259ad0.png

圖 smc-r發(fā)送接收(轉自阿里云)

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

09853874-3b5d-11ee-9e74-dac502259ad0.png

Libvma:

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

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

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

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

09a4998a-3b5d-11ee-9e74-dac502259ad0.png

總結:

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

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

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

05

總結與展望

前面主要分析和調研了一些開源應用在進行業(yè)務適配RDMA傳輸?shù)姆桨福w來看RDMA改造的方案是分為兩部分,分別為通信接口的改造以及RDMA內存管理設計。 通信接口改造主要指將tcp socket的傳輸接口修改為ib verbs或者cm接口,這部分同時涉及到適配現(xiàn)有業(yè)務網絡事件的處理模型。 由于RDMA傳輸數(shù)據(jù)時,需要預先將內存注冊到HCA卡上,所以RDMA內存管理會比較復雜,同時也是性能高低與否的關鍵。

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

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

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

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

應用名稱 網絡處理模型 內存方案 其他特性
Redis (pr stage) 1.適配原有的單線程reactor非阻塞模式
2.rdma無pollout時間,在業(yè)務邏輯中額外處理
3.網絡支持插件式,不同的傳輸模式實現(xiàn)相同的網絡方法
1.預注冊內存,RDMA Write模式
2.DMA地址通過控制消息交互
3.應用與RDMA之間存在拷貝
1.有控制面交互,如xferbuffer
2.控制面信息復用RDMA通道
Tensorflow 異步發(fā)送、阻塞接收 1.RDMA Write模式
2.應用及RDMA共享內存池
3.通信雙方通過消息交互DMA地址
1.使用基于TCP的GRPC通道進行RDMA鏈接的協(xié)商
2.有控制面消息交互,如metadata更新
3.控制面信息復用RDMA通道
BRPC reactor模式 1.內存池模式
2.使用RDMA Send模式
1.額外的流控機制
2.事件聚合
NCCL 1.reactor模式
2.網絡支持插件式,不同的傳輸模式實現(xiàn)相同的網絡方法
1.RDMA Write模式
2.通信雙方通過一個共享fifo來交互具體的DMA地址
3.DMA地址是預先注冊的內存
1.RDMA建立階段使用TCP鏈接進行協(xié)商

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






審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 處理器
    +關注

    關注

    68

    文章

    19028

    瀏覽量

    228441
  • RPC
    RPC
    +關注

    關注

    0

    文章

    110

    瀏覽量

    11483
  • RDMA
    +關注

    關注

    0

    文章

    75

    瀏覽量

    8906
  • TCP通信
    +關注

    關注

    0

    文章

    146

    瀏覽量

    4192
  • TLS
    TLS
    +關注

    關注

    0

    文章

    44

    瀏覽量

    4220

原文標題:RDMA在典型場景下的技術應用分析與探索

文章出處:【微信號:OSC開源社區(qū),微信公眾號:OSC開源社區(qū)】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    深入了解RDMA技術

    Explorer,專注于高性能網絡、虛擬化網絡及網卡的測試方案研究。熟悉dpdk,rdma,sdn等技術的應用與解決方案。
    的頭像 發(fā)表于 12-26 09:23 ?1509次閱讀
    深入了解<b class='flag-5'>RDMA</b>技術

    RDMA RNIC虛擬化方案

    遠程直接內存訪問(Remote Direct Memory Access,RDMA)技術允許應用程序繞過操作系統(tǒng)內核,以零拷貝的方式和遠程計算機進行網絡通信,具有低延遲和高帶寬的優(yōu)勢。RDMA協(xié)議
    的頭像 發(fā)表于 01-23 17:23 ?1569次閱讀
    <b class='flag-5'>RDMA</b> RNIC虛擬化<b class='flag-5'>方案</b>

    數(shù)字電視改造方案

    請問有誰做過這種改造工程啊?    我也想做這個啊方案基本原理:用30多個機頂盒調制出30多個頻道的模擬信號,供給100-200個房間都能收看30多個頻道。酒店按
    發(fā)表于 11-05 09:40

    Redis Stream應用案例

    的IoT設備會形成巨大的數(shù)據(jù)洪流,采集完成后在云端進行分析,產生巨大的用戶價值。這些數(shù)據(jù)雖然內容各個不同,但是都有一個共同的特點,都是一種時序數(shù)據(jù)??吹竭@里,你可能會突然發(fā)現(xiàn),Redis Stream從
    發(fā)表于 06-26 17:15

    Redis緩存和MySQL數(shù)據(jù)不一致原因和解決方案

    高并發(fā)架構系列:Redis緩存和MySQL數(shù)據(jù)一致性方案詳解
    發(fā)表于 03-27 15:55

    請問如何分析、排查、解決Redis變慢問題

    如何分析、排查、解決Redis變慢問題
    發(fā)表于 11-09 08:03

    簡要分析Redis的特性

    淺談Redis的數(shù)據(jù)結構、虛擬內存等特性2016-03-28 10:42 在這篇文章中,我們將談論 Redis(REmote DIctionary Server)。Redis是一個開源的、內存式
    發(fā)表于 10-11 15:21 ?0次下載
    簡要<b class='flag-5'>分析</b><b class='flag-5'>Redis</b>的特性

    redis和mongodb數(shù)據(jù)庫對比_redis、memcache、mongoDB 對比

    本文是對redis和mongodb數(shù)據(jù)庫對比分析。以及redis、memcache、mongoDB 區(qū)別對比。MongoDB和Redis都是NoSQL,采用結構型數(shù)據(jù)存儲。二者在使用場
    發(fā)表于 02-07 08:45 ?4210次閱讀
    <b class='flag-5'>redis</b>和mongodb數(shù)據(jù)庫對比_<b class='flag-5'>redis</b>、memcache、mongoDB 對比

    技術盛宴 | 淺析RDMA網絡下MMU水線設置

    )水線是保證RDMA網絡無損和低延時的關鍵。本文將以RDMA網絡作為切入點,結合實際部署經驗,分析MMU水線設置的一
    發(fā)表于 11-22 12:44 ?1091次閱讀

    redis工作原理

    一頭霧水。 很多時候,Redis出現(xiàn)訪問延遲變大,都與我們的使用不當或運維不合理導致的。 這篇文章我們就來分析一下Redis在使用過程中,經常會遇到的延遲問題以及如何定位和分析。 使用
    的頭像 發(fā)表于 09-24 15:57 ?3514次閱讀

    全面分析Redis的最佳實踐優(yōu)化

    這篇文章我想和你聊一聊 Redis 的最佳實踐。 你的項目或許已經使用 Redis 很長時間了,但在使用過程中,你可能還會或多或少地遇到以下問題: 我的 Redis 內存為什么增長這么快? 為什么我
    的頭像 發(fā)表于 04-26 10:51 ?1809次閱讀

    RDMA是什么?RDMA網卡有什么作用?

    近幾年RDMA這個詞在行業(yè)內炒的如火如荼,但是很多人表示RDMA具體是什么?主要應用在哪些領域,有什么作用?RDMA都有哪幾種協(xié)議?今天小編就這幾個問題給大家科普一下。
    發(fā)表于 12-27 17:15 ?1.2w次閱讀

    RDMA技術簡介 RDMA的控制通路和數(shù)據(jù)通路方案

    RDMA 技術基于傳統(tǒng)以太網的網絡概念,但與以太網網絡中的同類技術存在差異。關鍵區(qū) 別在于,RDMA 提供了一種消息服務,應用程序可以使用該服務直接訪問遠程計算機上的虛擬內存。
    發(fā)表于 04-10 09:59 ?1642次閱讀

    Redis數(shù)據(jù)同步解決方案—NineData

    NineData(https://www.ninedata.cloud/)在Redis的同步上,提供了穩(wěn)定和高效的解決方案,并且性能上也領先其他同步工具,特別是在同步的動態(tài)限流、數(shù)據(jù)對比修復和限流
    的頭像 發(fā)表于 06-05 15:31 ?776次閱讀
    <b class='flag-5'>Redis</b>數(shù)據(jù)同步解決<b class='flag-5'>方案</b>—NineData

    redis容器內怎么查看redis日志

    redis是一款流行的開源內存數(shù)據(jù)庫,常用于緩存、消息隊列、任務管理等場景。在使用redis時,了解如何查看redis日志對于排查問題、監(jiān)控性能和分析應用程序行為非常重要。在本文中,我
    的頭像 發(fā)表于 12-05 10:10 ?3194次閱讀