Ceph Async RDMA网络通信性能优化
Ceph Async RDMA網絡性能優化
濟南友泉軟件有限公司
?
目錄
一、???????? 現有代碼分析
1.1.?????? Reactor模型
1.1.1.??? Reactor模型的優點
1.1.2.??? Reactor模型的優點.
1.2.?????? 有限狀態機模型
1.3.?????? Async模塊
1.2.1.??? Async工作原理
1.2.2.??? Async主要組件
1.4.?????? RDMA
1.3.1.??? RDMA三種不同的硬件實現
1.3.2.??? 相關組件
二、???????? 性能優化工作匯總
2.1??????? RDMA網絡通信配置
2.2??????? RoCE網絡通信的實現
2.3??????? 性能測試平臺開發
2.2.1??? aysnc_server/async_client
2.2.2??? ceph_perf_msgr_server/ceph_perf_msgr_client
2.4??????? QueuePair發送隊列
2.5??????? TCMalloc優化內存分配
2.6??????? 工作線程數調優
2.7??????? 多線程Reactor模型
2.8??????? 消息接收緩存
附錄(Ⅰ):連接過程狀態遷移圖
參閱資料
?
- 現有代碼分析
網絡通信模塊的實現在源代碼src/msg的目錄下,該目錄主要包括Messenger、Connection、Message、Dispatch等類,這些類定義了網絡通信的框架與接口。三個子目錄simple、async、xio分別對應三種不同的網絡通信模型。simple、xio在最新的版本中已經被廢棄,async是目前系統默認的網絡通信方式。因此,本次網絡通信優化的工作主要在async基礎之上開展。
Reactor模型
為了處理高并發的網絡I/O流,async模塊采用了Reactor模型。在Reactor中,每一種handler會出處理一種event。這里會有一個全局的管理者selector,我們需要把channel注冊感興趣的事件,那么這個selector就會不斷在channel上檢測是否有該類型的事件發生,如果沒有,那么主線程就會被阻塞,否則就會調用相應的事件處理函數即handler來處理。
Reactor模型原理
Reactor模型主要組件
響應快,不必為單個同步時間所阻塞,雖然Reactor本身依然是同步的;編程相對簡單,可以最大程度的避免復雜的多線程及同步問題,并且避免了多線程/進程的切換開銷; 可以方便的通過增加Reactor實例個數來充分利用CPU資源;reactor框架本身與具體事件處理邏輯無關,具有很高的復用性;
相比傳統的簡單模型,Reactor增加了一定的復雜性,因而有一定的門檻,并且不易于調試; Reactor模式需要底層的Synchronous Event Demultiplexer支持,比如Java中的Selector支持,操作系統的select系統調用支持,如果要自己實現Synchronous Event Demultiplexer可能不會有那么高效;Reactor模式在IO讀寫數據時還是在同一個線程中實現的,即使使用多個Reactor機制的情況下,那些共享一個Reactor的Channel如果出現一個長時間的數據讀寫,會影響這個Reactor中其他Channel的相應時間,比如在大文件傳輸時,IO操作就會影響其他Client的相應時間,因而對這種操作,使用傳統的Thread-Per-Connection或許是一個更好的選擇,或則此時使用Proactor模式。
有限狀態機(Finite State Machine, FSM),是表示有限個狀態以及在這些狀態之間的轉移和動作等行為的數學模型。
FSM模型把模型的多狀態、多狀態間的轉換條件解耦;可以使維護變得容易,代碼也更加具有可讀性。
AsyncConnection連接建立過程中地狀態遷移圖參閱附錄(Ⅰ)。
?
| AsyncMessenger | 管理網絡連接 |
| AsyncConnection | 網路通信連接,定義網絡通信應用層協議 |
| NetworkStack | 管理Worker對象及其對應地線程 |
| Worker | 網絡I/O流處理單元,每個Worker對應一個工作線程 |
| ServerSocket/ServerSocketImpl | C/S模式監聽套接字,向上屏蔽了各種不同的網絡編程接口 |
| ConnectedSocket/ConnectedSocketImpl | C/S模式連接套接字,向上屏蔽了各種不同的網絡編程接口 |
| EventCenter | 事件分發器,負責事件注冊、事件分發 |
| EventCallback | 當對應的事件發生時,由EventCenter負責回調 |
| EventEpoll | 對epoll進行封裝,輪詢網絡I/O事件 |
?
RDMA是Remote Direct Memory Access的縮寫,通俗的說可以看成是遠程的DMA技術,為了解決網絡傳輸中服務器端數據處理的延遲而產生的。
???????????????????????? RDMA工作原理
目前,有三種RDMA協議的實現:Infiniband、RoCE、iWARP。由于RoCE具備明顯性能和成本優勢,將逐漸成為市場主流。
軟件棧對比
?
| ? | Infiniband (IB) | iWARP | RoCE |
| 標準組織 | IBTA | IETF | IBTA |
| 性能 | 最好 | 稍差 | 與IB相當 |
| 成本 | 高 | 中 | 低 |
| 網卡廠商 | Mellanox | Chelsio | Mellanox Emulex |
性能、成本對比
?
Infiniband網絡最好,但網卡和交換機是價格也很高,然而RoCEv2和iWARP僅需使用特殊的網卡就可以了,價格也相對便宜很多。
| Device/DeviceList | 抽象RDMA網卡,根據icfs.conf配置網卡參數 |
| Infiniband | 封裝IB Verbs網絡編程接口及組件 |
| RDMAConnectedSocketImpl | 仿socket連接套接字,采用偽fd實現網絡I/O流的數據讀寫 |
| RDMAConnTCP | 為RDMAConnectedSocketImpl服務,利用利用TCP/IP協議建立RDMA連接 |
| RDMAServerSocketImpl | 仿socket服務套接字,定義服務接口 |
| RDMAServerConnTCP | 實現RDMAServerSocketImpl接口,利用TCP/IP協議建立RDMA連接 |
| ? RDMADispatcher | 輪詢RDMA網絡I/O流可讀事件,將網絡I/O流可讀數據分發到對應RDMAConnectedSocketImpl 輪詢RDMA網絡I/O流可寫事件,將網絡I/O流可寫數據分發到某個RDMAWorker |
| RDMAWorker | 網絡I/O流處理單元,每個RDMAWorker對應一個工作線程 |
| RDMAStack | 管理RDMAWorker對象及其對應地線程 |
?
?
?
- 性能優化工作匯總
在安裝完網卡及其驅動之后,需要啟動openibd,運行以下命令
service openibd start
chkconfig openibd on
對于IB網絡,還需要啟動opensmd,
service opensmd start
chkconfig opensmd on
網絡啟動之后,通過ibstat可以查看當前網絡設備狀態,
[root@server42 ~]# ibstat
CA 'mlx5_0'
???? CA type: MT4119
???? Number of ports: 1
???? Firmware version: 16.25.1020
???? Hardware version: 0
???? Node GUID: 0xb8599f0300bd417a
???? System image GUID: 0xb8599f0300bd417a
???? Port 1:
????????????? State: Active
????????????? Physical state: LinkUp
????????????? Rate: 40
????????????? Base lid: 0
????????????? LMC: 0
????????????? SM lid: 0
????????????? Capability mask: 0x04010000
????????????? Port GUID: 0xba599ffffebd417a
????????????? Link layer: Ethernet
CA 'mlx5_1'
???? CA type: MT4119
???? Number of ports: 1
???? Firmware version: 16.25.1020
???? Hardware version: 0
???? Node GUID: 0xb8599f0300bd417b
???? System image GUID: 0xb8599f0300bd417a
???? Port 1:
????????????? State: Active
????????????? Physical state: LinkUp
????????????? Rate: 40
????????????? Base lid: 0
????????????? LMC: 0
????????????? SM lid: 0
????????????? Capability mask: 0x04010000
????????????? Port GUID: 0xba599ffffebd417b
????????????? Link layer: Ethernet
通過ib_send_bw、ib_send_lat等工具可以測試網絡帶寬、延遲等性能。
Async提供了posix、rdma兩種底層網絡通信的方式,為了使用RDMA協議實現高帶寬、低延遲的網絡通信,需要配置rdma網絡及軟件定義參數。
使用rdma verbs創建QueuePair時,需要通信雙方rdma設備的硬件信息,通常利用TCP/IP完成rdma連接雙方的硬件參數的交換,因此需要配置集群網段,即
public_network = 100.7.45.0/20
cluster_network = 188.188.44.0/20
Async模塊默認采用TCP/IP協議進行網絡通信,需要改成rdma協議
ms_type = async
ms_async_transport_type = rdma
RDMA Verbs API按照設備名對設備進行操作,為了兼容Linux操作系統的命名,需要進行設備網絡名到設備名的轉換,Mellanox驅動提供了以下命令用于獲取設備名與網絡名之間的映射關系:
[root@server42 ~]# ibdev2netdev
i40iw0 port 1 ==> eno1 (Up)
mlx5_0 port 1 ==> enp59s0f0 (Up)
mlx5_1 port 1 ==> enp59s0f1 (Up)
據此,可以在配置環境中設置網絡通信設備的名稱,即
ms_async_rdma_public_device_name = enp59s0f0
ms_async_rdma_cluster_device_name = enp59s0f1
由于Infiniband與RoCE網絡開發采用相同上層Verbs API,因此,IB網絡通信代碼可以完全在RoCE硬件上運行,整個代碼幾乎不需要改動。
為了能夠對網絡模塊通信性能及優化效果進行定性、定量地深入研究,需要一套相對獨立地RDMA網絡通信性能測試工具。
async_client向async_server發送MSG_DATA_PING類型地數據包,async_server當受到2000個數據包之后會自動關閉連接,async_client監測到async_server端關閉之后,async_client會停止發送數據包,同時輸出網絡通信性能地統計信息。
async_server命令參數
--addr X ip to listen
--port X port to bind
?
async_client命令參數:
--msgs X number of msg to transport
--dszie X size of each msg to transport
--addr X ip of the server
--port X port of the server
這種測試工具其實是利用async_server端連接關閉作為消息數據包發送結束的標志,因為async_client感知到async_server連接關閉需要一定的時間,從而導致不能夠準確地測試網絡性能。
采用“請求-應答”模式,具體實現上與實際的OSD業務通信流程比較相似,因此可以較好的反映網絡通信性能。
client向server端發送指定數量的MOSDOp消息,server端對于收到的每個MOSDOp消息,都會向client端發送MOSDOpReply消息。
但是,ceph_perf_msgr_client在ClientThread::entry()中存在一個Bug,即
??? void *entry() {
????? lock.Lock();
????? for (int i = 0; i < ops; ++i) {
??????? if (inflight > uint64_t(concurrent)) {
????????? cond.Wait(lock);
??????? }
??????? MOSDOp *m = new MOSDOp(client_inc.read(), 0, oid, oloc, pgid, 0, 0, 0);
????? ??m->write(0, msg_len, data);
??????? inflight++;
??????? conn->send_message(m);
??????? //cerr << __func__ << " send m=" << m << std::endl;
????? }
由于調用write()函數之后,data內的數據會被清空,所以第一次調用之后,后面發送的數據包其實沒有數據,需要改成
??? void *entry() {
????? lock.Lock();
????? for (int i = 0; i < ops; ++i) {
??????? if (inflight > uint64_t(concurrent)) {
????????? cond.Wait(lock);
??????? }
??????? MOSDOp *m = new MOSDOp(client_inc.read(), 0, oid, oloc, pgid, 0, 0, 0);
??????? /*
??????? m->write(0, msg_len, data);
??????? */
??????? bufferlist msg_data(data);
??????? m->write(0, msg_len, msg_data);
?
??????? inflight++;
??????? conn->send_message(m);
??????? //cerr << __func__ << " send m=" << m << std::endl;
????? }
????? lock.Unlock();
????? msgr->shutdown();
???? ?return 0;
}
?
| server 41 | server 42 | Client性能 | ||||
| Server配置 | Client | |||||
| 并行數 | 并行數 | 隊列深度 | request個數 | 耗時(us) | IOPS | 延時(us) |
| 1 | 1 | 32 | 100K | 4324564 | 23123.72 | 43.24564 |
| 1 | 2 | 32 | 100K | 3464919 | 57721.41 | 34.64919 |
| 1 | 4 | 32 | 100K | 4003939 | 99901.62 | 40.03939 |
| 1 | 8 | 32 | 100K | 5313240 | 150567.3 | 53.1324 |
| 1 | 16 | 32 | 100K | 11167830 | 143268.7 | 111.6783 |
| 1 | 32 | 32 | 100K | 27079705 | 118169.7 | 270.7971 |
| 1 | 64 | 32 | 100K | 68204271 | 93835.77 | 682.0427 |
| 1 | 64 | 64 | 100K | 66653653 | 96018.74 | 666.5365 |
?
?
?
?
| server 41 | server 42 | Client性能 | ||||
| Server配置 | Client | |||||
| 并行數 | 并行數 | 隊列深度 | request個數 | 耗時(us) | IOPS | 延時(us) |
| 1 | 1 | 32 | 100K | 4952843 | 20190.424 | 49.52843 |
| 1 | 2 | 32 | 100K | 3712582 | 53870.864 | 37.12582 |
| 1 | 4 | 32 | 100K | 3664009 | 109170.038 | 36.64009 |
| 1 | 8 | 32 | 100K | 5526721 | 144751.291 | 55.26721 |
| 1 | 16 | 32 | 100K | 11834255 | 135200.737 | 118.3426 |
| 1 | 32 | 32 | 100K | 33805670 | 94658.6771 | 338.0567 |
| 1 | 64 | 32 | 100K | 67214894 | 95216.9916 | 672.1489 |
| 1 | 64 | 64 | 100K | 68273589 | 93740.4946 | 682.7359 |
?
從以上測試結果來看,主要有以下結論:
- 無論采用polling還是event輪詢模式,網絡性能幾乎一樣。
- 隨著連接數的增大,網絡性能逐漸達到性能瓶頸,最大IOPS為14萬左右。
- 當連接數增大到一定程度,IOPS維持在9萬左右。
通過讀取ms_async_rdma_receive_buffer與ms_async_rdma_send_buffers來配置注冊內存大小,在Device::create_queue_pair()中,會根據ms_async_rdma_send_buffers來創建QueuePair.,即
Infiniband::QueuePair* Device::create_queue_pair(IcfsContext *cct, ibv_qp_type type)
{
? Infiniband::QueuePair *qp = new QueuePair(
????? cct, *this, type, active_port->get_port_num(), srq, rx_cq, rx_cq, max_send_wr, max_recv_wr);
?
? if (qp->init()) {
??? delete qp;
??? return NULL;
? }
? return qp;
}
?
但是ms_async_rdma_send_buffers設置較大會導致創建QueuePair失敗,需要獨立地設置注冊內存以及QueuePair的創建,
Infiniband::QueuePair* Device::create_queue_pair(IcfsContext *cct, ibv_qp_type type)
{
//<nene>: use the "ms_async_rdma_qp_max_send_wr" instead of "max_send_wr"
/*
? Infiniband::QueuePair *qp = new QueuePair(
????? cct, *this, type, active_port->get_port_num(), srq, rx_cq, rx_cq, max_send_wr, max_recv_wr);
*/
? uint32_t qp_max_send_wr = cct->_conf->ms_async_rdma_qp_max_send_wr;
? Infiniband::QueuePair *qp = new QueuePair(
????? cct, *this, type, active_port->get_port_num(), srq, rx_cq, rx_cq, qp_max_send_wr, max_recv_wr);
//</nene>
? if (qp->init()) {
??? delete qp;
??? return NULL;
? }
? return qp;
}
經過修改之后,達到了以下效果,
- 注冊內存buffer大小(ms_async_rdma_buffer_size)可由4096增加到131072
- 注冊內存buffer數量(ms_async_rdma_send_buffers/ms_async_receive_buffers)可由1024增加到10240
- 解決了1M大小數據塊測試過程中數據斷流問題
TCMalloc全稱Thread-Caching Malloc,即線程緩存的malloc,實現了高效的多線程內存管理,用于替代系統的內存分配相關的函數(malloc、free,new,new[]等)。
icfs_perf_msgr_server/icfs_perf_msgr_client測試工具沒有采用TCMalloc,但是msg模塊卻使用了TCMAlloc進行優化,為了更加準確地描述網絡模塊地性能,需要對測試程序配置對TCMalloc的支持。
在測試程序中采用TCMalloc分配內存,測試結果如下,
| server 41 | server 42 | Client性能 | ||||
| Server配置 | Client | |||||
| 并行數 | 并行數 | 隊列深度 | request個數 | 耗時(us) | IOPS | 延時(us) |
| 1 | 1 | 32 | 100K | 3208947 | 31162.87 | 32.08947 |
| 1 | 2 | 32 | 100K | 3432609 | 58264.72 | 34.32609 |
| 1 | 4 | 32 | 100K | 3349781 | 119410.8 | 33.49781 |
| 1 | 8 | 32 | 100K | 4502944 | 177661.5 | 45.02944 |
| 1 | 16 | 32 | 100K | 6317459 | 253266.4 | 63.17459 |
| 1 | 32 | 32 | 100K | 12766794 | 250650.2 | 127.6679 |
| 1 | 64 | 32 | 100K | 25002414 | 255975.3 | 250.0241 |
| 1 | 64 | 64 | 100K | 25310469 | 252859.8 | 253.1047 |
從上面地優化結果可以看出,
- 經過TCMalloc內存分配優化,最大IOPS增加近160%。
- 連接數增大到一定程度,整體性能不再提高,1S1C情況下,最大IOPS為25萬左右。
每個AsyncMessenger根據ms_async_op_threads生成Worker線程,每個Worker線程包含一個事件分發器EventCenter來處理網絡I/O流事件及其回調函數分發。
對于單個AsyncMessenger,增大ms_async_op_threads,生成多個Worker線程,研究不同情況地網絡通信性能。
?
?
?
| server 41 | server 42 | Client性能 | CPU占有率 | ||||
| Server配置 | Client | ||||||
| 并行數 | 并行數 | 隊列深度 | request個數 | 耗時(us) | IOPS | 延時(us) | |
| 1 | 1 | 32 | 100K | 3331462 | 30016.85 | 33.31462 | 69.1% |
| 1 | 2 | 32 | 100K | 3372494 | 59303.29 | 33.72494 | 133.4% |
| 1 | 4 | 32 | 100K | 3927981 | 101833.5 | 39.27981 | 231.1% |
| 1 | 8 | 32 | 100K | 6795892 | 117718.2 | 67.95892 | 284.8% |
| 1 | 16 | 32 | 100K | 11972282 | 133642 | 119.7228 | 343% |
| 1 | 32 | 32 | 100K | 19545797 | 163718.1 | 195.458 | 342.9% |
| 1 | 64 | 32 | 100K | 34377666 | 186167.4 | 343.7767 | 362.8% |
| 1 | 64 | 64 | 100K | 29780075 | 214908.8 | 297.8008 | 369.5% |
?
?
| server 41 | server 42 | Client性能 | CPU占有率 | ||||
| Server配置 | Client | ||||||
| 并行數 | 并行數 | 隊列深度 | request個數 | 耗時(us) | IOPS | 延時(us) | |
| 1 | 1 | 32 | 100K | 3208947 | 31162.87 | 32.08947 | 53.5% |
| 1 | 2 | 32 | 100K | 3432609 | 58264.72 | 34.32609 | 114.6% |
| 1 | 4 | 32 | 100K | 3349781 | 119410.8 | 33.49781 | 249% |
| 1 | 8 | 32 | 100K | 4502944 | 177661.5 | 45.02944 | 356% |
| 1 | 16 | 32 | 100K | 6317459 | 253266.4 | 63.17459 | 616% |
| 1 | 32 | 32 | 100K | 12766794 | 250650.2 | 127.6679 | 654% |
| 1 | 64 | 32 | 100K | 25002414 | 255975.3 | 250.0241 | 649% |
| 1 | 64 | 64 | 100K | 25310469 | 252859.8 | 253.1047 | 691% |
?
從結果來看,Worker線程數由3增加到10,最大IOPS增加19%,但是相應地CPU占有率增加近87%。
Async模塊采用Reactor模型,當網絡I/O流事件發生時,EventCenter會調用對應對應地事件回調函數EventCallback進行處理,由于同一EventCenter內地事件回調函數地執行是順序地,所以當存在較耗時地回調函數調用時,EventCenter::process_events就成為了整個網絡通信性能瓶頸。
為了改進這種高性能網絡I/O流模型,主要有兩種思路:
- 增加EventCenter地數量,達到降低單個EventCenter內地事件回調數量地目的。
- 采用多線程模型,異步地執行同一EventCenter內的事件回調。
經過測試分析,多線程Reactor模型并未達到預期地效果,性能沒有提升。
主要代碼如下:
ThreadPool cb_tp;
? class EventCallbackWQ : public ThreadPool::WorkQueue<EventCallback> {
??? list<EventCallback*> callbacks;
?
?? public:
??? EventCallbackWQ(time_t timeout, time_t suicide_timeout, ThreadPool *tp)
????? : ThreadPool::WorkQueue<EventCallback>("EventCenter::EventCallback", timeout, suicide_timeout, tp) {}
?
??? bool _enqueue(EventCallback *cb) {
????? auto iter = std::find(callbacks.begin(), callbacks.end(), cb);
????? if (iter == callbacks.end()) {
??????? callbacks.push_back(cb);
????? }
????? return true;
??? }
??? void _dequeue(EventCallback *cb) {
????? assert(0);
??? }
??? bool _empty() {
????? return callbacks.empty();
??? }
??? EventCallback *_dequeue() {
????? if (callbacks.empty())
??????? return NULL;
????? EventCallback *cb = callbacks.front();
????? callbacks.pop_front();
????? return cb;
??? }???
??? void _process(EventCallback *cb, ThreadPool::TPHandle &handle) override {
????? if (cb) {
??????? cb->do_request(cb->fd_or_id);
????? } else {
??????? assert(0);
????? }
??? }
??? void _process_finish(EventCallback *cb) { }
??? void _clear() {
????? assert(callbacks.empty());
??? }
? } cb_wq;
?
當網絡I/O流存在可讀數據的時候,EventCenter::process_events()會調用AsyncConnection::process()函數來讀取消息數據。
在讀取消息的data部分的時候,會不斷地調用alloc_aligned_buffer()來申請內存,從而嚴重地影響程序地性能。為了提高內存分配地利用效率,通過封裝boost::pool內存池來完成bufferlist中內存分配。
目前這項工作還在進行中,需要進一步地分析驗證。
主要代碼如下:
? class buffer::boost_buffer : public buffer::raw {
??? boost::pool<> &mempool;
??? unsigned chunk_size = 0;
??? unsigned chunk_num = 0;
? public:
??? explicit boost_buffer(unsigned l, boost::pool<> &p) : raw(l), mempool(p) {
????? if (len) {
??????? chunk_size = p.get_requested_size();
??????? chunk_num = len/chunk_size+1;
??????? if (len%chunk_size==0) {
????????? --chunk_num;
??????? }
??????? data = static_cast<char *>(mempool.ordered_malloc(chunk_num));
????? }
?
????? assert(data != nullptr);
?
????? inc_total_alloc(len);
????? bdout << "boost_buffer" << this << " alloc " << (void *)data << " " << l << " " << buffer::get_total_alloc() << bendl;
??? }
??? ~boost_buffer() {
????? mempool.ordered_free(data, chunk_num);
?
????? dec_total_alloc(len);
????? bdout << "boost_buffer " << this << " free " << (void *)data << " " << buffer::get_total_alloc() << bendl;
??? }
??? raw* clone_empty() {
????? return new boost_buffer(len, mempool);
??? }
? };
? buffer::raw* buffer::create_boost_buffer(unsigned len, boost::pool<> &p) {
??? return new buffer::boost_buffer(len, p);
? }
?
static void alloc_boost_buffer(boost::pool<> &p, unsigned len, bufferlist &data)
{
? // create a buffer to read into that matches the data alignment
? assert(len != 0);
?
? bufferptr ptr
? (
??? buffer::create_boost_buffer
??? (
????? len, p
??? )
? );
? data.push_back(std::move(ptr));
}
?
????? case STATE_OPEN_MESSAGE_READ_DATA_PREPARE:
??????? {
????????? // read data
????????? unsigned data_len = le32_to_cpu(current_header.data_len);
????????? unsigned data_off = le32_to_cpu(current_header.data_off);
????????? if (data_len) {
??????????? // get a buffer
??????????? map<icfs_tid_t,pair<bufferlist,int> >::iterator p = rx_buffers.find(current_header.tid);
?????? ?????if (p != rx_buffers.end()) {
????????????? ldout(async_msgr->cct,10) << __func__ << " seleting rx buffer v " << p->second.second
????????????????????????????????? << " at offset " << data_off
????????????????????????????????? << " len " << p->second.first.length() << dendl;
????????????? data_buf = p->second.first;
????????????? // make sure it's big enough
????????????? if (data_buf.length() < data_len)
??????????????? data_buf.push_back(buffer::create(data_len - data_buf.length()));
????????????? data_blp = data_buf.begin();
??????????? } else {
????????????? ldout(async_msgr->cct,20) << __func__ << " allocating new rx buffer at offset " << data_off << dendl;
????????????? //<nene>: Use the memepool
????????????? //alloc_aligned_buffer(data_buf, data_len, data_off);
????????????? alloc_boost_buffer(mempool, data_len, data_buf);
????????????? data_blp = data_buf.begin();
??????????? }
????????? }
?
????????? msg_left = data_len;
????????? state = STATE_OPEN_MESSAGE_READ_DATA;
??????? }
?
?
附錄(Ⅰ):連接過程狀態遷移圖
?
?
參閱資料
總結
以上是生活随笔為你收集整理的Ceph Async RDMA网络通信性能优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GCD分析
- 下一篇: Proxy Error错误解决方法