您好,登錄后才能下訂單哦!
RDMA該怎么用,相信很多沒有經(jīng)驗(yàn)的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個(gè)問題。
如今,服務(wù)器的網(wǎng)絡(luò)帶寬越來越高。當(dāng)網(wǎng)絡(luò)帶寬邁過萬兆這條線后,操作系統(tǒng)用于處理網(wǎng)絡(luò)IO的開銷就越來越難以忽視。在一些網(wǎng)絡(luò)IO密集的業(yè)務(wù)中,操作系統(tǒng)本身成為了網(wǎng)絡(luò)通信的瓶頸,這不僅會導(dǎo)致調(diào)用時(shí)延的增加(尤其是長尾),還會影響到服務(wù)的整體吞吐。
相對于網(wǎng)絡(luò)帶寬的發(fā)展速度,CPU性能的發(fā)展停滯是導(dǎo)致上述問題的主要原因。 因此,想從根本上解決CPU參與網(wǎng)絡(luò)傳輸?shù)牡托栴},就要更多地借助專用芯片的能力,RDMA高性能網(wǎng)絡(luò)勢不可擋。
RDMA(Remote Direct Memory Access),可以簡單理解為網(wǎng)卡完全繞過CPU實(shí)現(xiàn)兩個(gè)服務(wù)器之間的內(nèi)存數(shù)據(jù)交換。其作為一種硬件實(shí)現(xiàn)的網(wǎng)絡(luò)傳輸技術(shù),可以大幅提升網(wǎng)絡(luò)傳輸效率,幫助網(wǎng)絡(luò)IO密集的業(yè)務(wù)(比如分布式存儲、分布式數(shù)據(jù)庫等)獲得更低的時(shí)延以及更高的吞吐。
具體來說,RDMA技術(shù)的應(yīng)用要借助支持RDMA功能的網(wǎng)卡以及相應(yīng)的驅(qū)動(dòng)程序。由下圖所示,一旦應(yīng)用程序分配好資源,其可以直接把要發(fā)送的數(shù)據(jù)所在的內(nèi)存地址和長度信息交給網(wǎng)卡。網(wǎng)卡從內(nèi)存中拉取數(shù)據(jù),由硬件完成報(bào)文封裝,然后發(fā)送給對應(yīng)的接收端。接收端收到RDMA報(bào)文后,直接由硬件解封裝,取出數(shù)據(jù)后,直接放在應(yīng)用程序預(yù)先指定的內(nèi)存位置。
由于整個(gè)IO過程無需CPU參與,無需操作系統(tǒng)內(nèi)核參與,沒有系統(tǒng)調(diào)用,沒有中斷,也無需內(nèi)存拷貝,因此RDMA網(wǎng)絡(luò)傳輸可以做到極高的性能。在極限benchmark測試中,RDMA的時(shí)延可以做到1us級別,而吞吐甚至可以達(dá)到200G。
需要注意的是,RDMA的使用需要應(yīng)用程序的代碼配合(RDMA編程)。與傳統(tǒng)TCP傳輸不同,RDMA并沒有提供socket API封裝,而是要通過verbs API來調(diào)用(使用libibverbs)。出于避免中間層額外開銷的考慮,verbs API采用了貼近硬件實(shí)現(xiàn)的語義形態(tài),導(dǎo)致使用方法與socket API差異巨大。 因此,對大多數(shù)開發(fā)者來說,無論是改造原有應(yīng)用程序適配RDMA,還是寫一個(gè)全新的RDMA原生的應(yīng)用程序,都不容易。
如圖所示,在socket API中,發(fā)送接收數(shù)據(jù)主要用到的接口如下:
Socket API
其中,write和read操作中的fd是標(biāo)識一個(gè)連接的文件描述符。應(yīng)用程序要發(fā)送的數(shù)據(jù),會通過write拷貝到系統(tǒng)內(nèi)核緩沖區(qū)中;而read實(shí)際上也是從系統(tǒng)內(nèi)核緩沖區(qū)中將數(shù)據(jù)拷貝出來。 在絕大多數(shù)應(yīng)用程序里,通常都會設(shè)置fd為非阻塞的,也就是說,如果系統(tǒng)內(nèi)核緩沖區(qū)已滿,write操作會直接返回;而如果系統(tǒng)內(nèi)核緩沖區(qū)為空,read操作也會直接返回。 為了在第一時(shí)間獲知內(nèi)核緩沖區(qū)的狀態(tài)變化,應(yīng)用程序需要epoll機(jī)制來監(jiān)聽EPOLLIN和EPOLLOUT事件。如果epoll_wait函數(shù)因這些事件返回,則可以觸發(fā)下一次的write和read操作。這就是socket API的基本使用方法。 作為對比,在verbs API中,發(fā)送接收數(shù)據(jù)主要用到的接口如下:
Verbs API
其中,ibv_是libibverbs庫中函數(shù)和結(jié)構(gòu)體的前綴。ibv_post_send近似于發(fā)送操作,ibv_post_recv近似于接收操作。發(fā)送接收操作里面的qp(queue pair)近似于socket API里面的fd,作為一個(gè)連接對應(yīng)的標(biāo)識。wr(work request)這個(gè)結(jié)構(gòu)體里包含了要發(fā)送/接收的數(shù)據(jù)所在的內(nèi)存地址(進(jìn)程的虛擬地址)和長度。ibv_poll_cq則作為事件檢測機(jī)制存在,類似于epoll_wait。
乍一看去,RDMA編程似乎很簡單,只要把上述函數(shù)替換了就可以。但事實(shí)上,上述的對應(yīng)關(guān)系都是近似、類似,而不是等價(jià)。 關(guān)鍵區(qū)別在于,socket API都是同步操作,而RDMA API都是異步操作(注意異步和非阻塞是兩個(gè)不同的概念)。
具體而言,ibv_post_send函數(shù)返回成功,僅僅意味著成功地向網(wǎng)卡提交了發(fā)送請求,并不保證數(shù)據(jù)真的被發(fā)送出去了。如果此時(shí)立馬對發(fā)送數(shù)據(jù)所在的內(nèi)存進(jìn)行寫操作,那么發(fā)送出去的數(shù)據(jù)就很可能是不正確的。socket API是同步操作,write函數(shù)返回成功,意味著數(shù)據(jù)已經(jīng)被寫入了內(nèi)核緩沖區(qū),雖然此時(shí)數(shù)據(jù)未必真的發(fā)送了,但應(yīng)用程序已經(jīng)可以隨意處置發(fā)送數(shù)據(jù)所在的內(nèi)存。
另一方面,ibv_poll_cq所獲取的事件,與epoll_wait獲取的事件也是不同的。前者表明,之前提交給網(wǎng)卡的某一發(fā)送或接收請求完成了;而后者表示,有新的報(bào)文被成功發(fā)送或是接收了。這些語義上的變化會影響到上層應(yīng)用程序的內(nèi)存使用模式和API調(diào)用方式。
除了同步、異步的語義區(qū)別外, RDMA編程還有一個(gè)關(guān)鍵要素,即所有參與發(fā)送、接收的數(shù)據(jù),所在的內(nèi)存必須經(jīng)過注冊。
所謂內(nèi)存注冊,簡單理解,就是把一段內(nèi)存的虛擬地址和物理地址間的映射關(guān)系綁定好以后注冊給網(wǎng)卡硬件。這么做的原因在于,發(fā)送請求和接收請求所提交的內(nèi)存地址,都是虛擬地址。只有完成內(nèi)存注冊,網(wǎng)卡才能把請求中的虛擬地址翻譯成物理地址,才能跳過CPU做直接內(nèi)存訪問。內(nèi)存注冊(以及解注冊)是一個(gè)很慢的操作,實(shí)際應(yīng)用中通常需要構(gòu)建內(nèi)存池,通過一次性注冊、重復(fù)使用來避免頻繁調(diào)用注冊函數(shù)。
關(guān)于RDMA編程,還有很多細(xì)節(jié)是普通網(wǎng)絡(luò)編程所不關(guān)心的(比如流控、TCP回退、非中斷模式等等),這里就不一一展開介紹了。 總而言之,RDMA編程并不是一件容易的事情。那么,如何才能讓開發(fā)者快速用上RDMA這樣的高性能網(wǎng)絡(luò)技術(shù)呢?
上面說了很多socket API和verbs API的對比,主要還是為了襯托RDMA編程本身的復(fù)雜度。事實(shí)上,在實(shí)際生產(chǎn)環(huán)境中,直接調(diào)用socket API進(jìn)行網(wǎng)絡(luò)傳輸?shù)臉I(yè)務(wù)并不多,絕大多數(shù)都通過rpc框架間接使用socket API。一個(gè)完整的rpc框架,需要提供一整套網(wǎng)絡(luò)傳輸?shù)慕鉀Q方案,包括數(shù)據(jù)序列化、錯(cuò)誤處理、多線程處理等等。 brpc是百度開源的一個(gè)基于C++的rpc框架,其相對于grpc更適用于有高性能需求的場景。在傳統(tǒng)TCP傳輸以外,brpc也提供了RDMA的使用方式,以進(jìn)一步突破操作系統(tǒng)本身的性能限制。有關(guān)具體的實(shí)現(xiàn)細(xì)節(jié),感興趣的朋友可以參見github上的源碼(https://github.com/apache/incubator-brpc/tree/rdma)。
brpc client端使用RDMA
brpc server端使用RDMA
上面分別列出了brpc中client和server使用RDMA的方法,即在channel和server創(chuàng)建時(shí),把use_rdma這個(gè)option設(shè)置為true即可(默認(rèn)是false,也就是使用TCP)。
是的,只需這兩行代碼。如果你的應(yīng)用程序本身基于brpc構(gòu)建,那么從TCP遷移到RDMA,幾分鐘就夠了。當(dāng)然,在上述quick start之后,如果有更高級的調(diào)優(yōu)需求,brpc也提供了一些運(yùn)行時(shí)的flag參數(shù)可調(diào)整,比如內(nèi)存池大小、qp/cq的大小、輪詢替代中斷等等。
下面通過echo benchmark說明brpc使用RDMA的性能收益(可以在github代碼中的rdma_performance目錄下找到該benchmark)。在25G網(wǎng)絡(luò)的測試環(huán)境中,對于2KB以下的消息,使用RDMA后,server端的最大QPS提高了50%以上,200k的QPS下平均時(shí)延下降了50%以上。
Echo benchmark下server端最大QPS(25G網(wǎng)絡(luò))
Echo benchmark在200k QPS下的平均時(shí)延(25G網(wǎng)絡(luò))
RDMA對echo benchmark的性能收益僅作為參考。實(shí)際應(yīng)用程序的workload與echo相差巨大。對于某些業(yè)務(wù),使用RDMA的收益可能會小于上述值,因?yàn)榫W(wǎng)絡(luò)部分的開銷僅占到其業(yè)務(wù)開銷的一部分。但對于另一些業(yè)務(wù),由于避免了內(nèi)核操作對業(yè)務(wù)邏輯的干擾,使用RDMA的收益甚至?xí)哂谏鲜鲋?。這里舉兩個(gè)應(yīng)用brpc的例子:
在百度分布式塊存儲業(yè)務(wù)中,使用RDMA相比于使用TCP,4KB fio時(shí)延測試的平均值下降了約30%(RDMA僅優(yōu)化了網(wǎng)絡(luò)IO,存儲IO則不受RDMA影響)。
在百度分布式內(nèi)存KV業(yè)務(wù)中,使用RDMA相比于使用TCP,200k QPS下,單次查詢30key的平均時(shí)延下降了89%,而99分位時(shí)延下降了96%。
RDMA是一種新興的高性能網(wǎng)絡(luò)技術(shù),對于通信兩端均可控的數(shù)據(jù)中心內(nèi)網(wǎng)絡(luò)IO密集業(yè)務(wù),如HPC、機(jī)器學(xué)習(xí)、存儲、數(shù)據(jù)庫等,意義重大。我們鼓勵(lì)相關(guān)業(yè)務(wù)的開發(fā)者關(guān)注RDMA技術(shù),嘗試?yán)胋rpc構(gòu)建自己的應(yīng)用以平滑遷移至RDMA。 但是,需要指出的是,RDMA當(dāng)前還無法像TCP那樣通用,有一些基礎(chǔ)設(shè)施層面的限制需要注意:
RDMA需要網(wǎng)卡硬件支持。常見的萬兆網(wǎng)卡一般不支持這項(xiàng)技術(shù)。
RDMA的正常使用有賴于物理網(wǎng)絡(luò)支持。
百度智能云在RDMA基礎(chǔ)設(shè)施方面積累了深厚的經(jīng)驗(yàn)。得益于先進(jìn)的硬件配置與強(qiáng)大的工程技術(shù),用戶可以在25G甚至是100G網(wǎng)絡(luò)環(huán)境中,通過物理機(jī)或容器,充分獲取RDMA技術(shù)帶來的性能收益,而將與業(yè)務(wù)無關(guān)的復(fù)雜的物理網(wǎng)絡(luò)配置工作(比如無損網(wǎng)絡(luò)PFC以及顯示擁塞通告ECN),交給百度智能云技術(shù)支持人員。歡迎對高性能計(jì)算、高性能存儲等業(yè)務(wù)有需求的開發(fā)者向百度智能云咨詢相關(guān)情況。
看完上述內(nèi)容,你們掌握RDMA該怎么用的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。