基於solarflare的openonload技術以TCPDirect方法加速epoll


【前言】基於solarflare的onload模式加速,官方文檔給出TCPDirect模式可以實現從300ns到30ns的延遲縮減。我們需要測試在我們的交易模型框架中他的延時,有人給出了tcpdirect加速大約會比onload模式快300ns左右,不是倍數關系,是一個數量差。雖未達如此高速交易,但量化交易,分秒必爭。但是tcpdirect有一個缺點就是必須使用它的接口,不像onload只需要安裝好加速環境,使用onload模式就可以了。TCPDirect需要拿到源碼,並重寫底層。

  我們實現一個類epoll-socket,TCPDirect使用了muxer,實現叫做zocket,進行RTT測試。

一、server端

  對應epoll,我們使用muxer實現,和epoll接口類似。

  1、注意后面要釋放掉創建的zf_muxer_free(muxer);

  2、因為我們使用內核旁路技術,不要使用zf_recv()函數,雖然他有返回接收數據的大小,但是他是基於copy的,使用zf_zc_recv()。

  3、每次在使用接口有數據交換或者使用硬件時,要使用zf_reactor_perform(stack);,因為我們的zocket是運行在一個初始化的stack上的,每次都要用此接口來進行“初始化”,文檔這樣寫的,我也不清楚。

  4、其他的和epoll不同之處要悉心,比如無需綁定,用zft_listen()綁定,zf_zc_recv和zf_send的存儲的數據結構也不相同,下面有我的兩種數據的轉換存儲方式,因為在服務器端需要進行一個轉存;

  5、測試時間的核心程序:

ZF_TRY(zf_muxer_add(muxer, zft_to_waitable(zock), &evs[i]));
 //初始化stack           
zf_reactor_perform(stack);
rd1.zcr.iovcnt = 1;
HP_TIMING_NOW(t0);
zft_zc_recv(zock, &rd1.zcr, 0);
if( rd1.zcr.iovcnt == 0 )
    continue;
if( first_recv ) {
    first_recv = 0;
    siov.iov_len = rd1.zcr.iov[0].iov_len;
    memcpy(buf, ((char*)rd1.zcr.iov[0].iov_base),siov.iov_len);
    }            
for( int i = 0 ; i < rd1.zcr.iovcnt; ++i ) {
    len3=zft_send(zock, &siov, 1, 0);
    }
    HP_TIMING_NOW(t1);
     //c++11的元組,編譯時候可能要加上-std=c++11           
    time_v.push_back(std::make_tuple(len3,t1, t0, (t1 - t0)));
    cout<<"服務器發送:"<<len3<<"數據:"<<buf<<endl;
            
    zft_zc_recv_done(zock, &rd1.zcr);

二、客戶端

  1、初始化的stack可能會用完,要加上ZF_TRY(zft_send_space(tcp,&send_size));,send_size是一個傳出參數,返回tcp連接的棧剩余空間,小於目標大小的時候要判斷,然后重新分配,我們僅是實現測試,足夠我用;

  2、測試結果,就在客戶端。我們需要發送和其他模式下同樣的數據,到server,然后返回,client再收到所用的時間。

  3、發送和接受和server一樣注意,此處無需裝換;

  4、輸出結果的代碼,使用tuple。mongodb那種nosql可以用這種數據組織方式存儲。

std::vector<std::tuple<int, u64_t, u64_t, int>>::iterator it;
for (it = time_v.begin(); it != time_v.end(); ++it) {
     cout << "len=" << std::get<0>(*it) << " --- recv time = " << std::get<1>(*it) << ", send time = " << std::get<2>(*it)
           << ", gap = " << std::get<3>(*it) << endl;
   if (it != time_v.begin()) {
          sum += std::get<3>(*it);
          ++num;
        }
    }
#第一個時間是jiffies,要除以本機的cpu主頻

 std::cout << "avg gap = " << (sum / (num*1.0) ) << endl;
 std::cout << "avg gap(ns) = " << (sum / (num*3.4)) << endl;

(關於jiffies和cpu頻率的關系:https://www.cnblogs.com/by-dream/p/5143192.html   相除就是時間)

    使用tcpdirect在char類型511字節數據上,進行RTT測試,循環1000次的平均用時3444納秒(3.5微秒)左右。

  具體和普通socket、使用onload加速的對比:

  當然,這只是個別。我大約測了10次,平均值大約如此。

三、收獲心得

1、學會了初步的gdb- 對於coredump情況調試方法,學會了一些分析錯誤的思路。

 2、tcpdump抓包分析,wireshark分析。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM