聶永的博客

          記錄工作/學(xué)習(xí)的點點滴滴。

          Fastsocket學(xué)習(xí)筆記之內(nèi)核篇

          前言

          前面分析Fastsocket慢慢湊成了幾篇爛文字,要把一件事情堅持做下來,有時味同爵蠟,但既然選擇了,也得硬著頭皮做下去。閑話少說,文歸正文。本文接自上篇內(nèi)核模塊篇,繼續(xù)記錄學(xué)習(xí)Fastsocket內(nèi)核的筆記內(nèi)容。

          Fastsocket建立在SO_REUSEPORT支持基礎(chǔ)上

          Linux kernel 3.9包含TCP/UDP支持多進程、多線程綁定同一個IP和端口的特性,即SO_REUSEPORT;在內(nèi)核層面同時也讓線程/進程之間各自獨享SOCKET,避免CPU核之間以鎖資源爭奪accept queue的調(diào)用。在fastsocket/kernel/net/sock.h定義sock_common結(jié)構(gòu)時,可以看到其身影:

          unsigned char          skc_reuse:4;
          unsigned char          skc_reuseport:4;
          

          在多個socket.h文件中(比如fastsocket/kernel/include/asm/socket.h),定義了SO_REUSESORT的變量值:

          #define SO_REUSEPORT     15
          

          在fastsocket/kernel/net/core/sock.c的sock_setsockopt和sock_getsockopt函數(shù)中,都有SO_REUSEPORT的身影:

          sock_setsockopt函數(shù)中:

          case SO_REUSEADDR:
            sk->sk_reuse = valbool;
            break;
          case SO_REUSEPORT:
            sk->sk_reuseport = valbool;
            break;
          

          sock_getsockopt函數(shù)體中:

          case SO_REUSEADDR:
            v.val = sk->sk_reuse;
            break;
          case SO_REUSEPORT:
            v.val = sk->sk_reuseport;
            break;
          

          SO_REUSEPORT特性支持之前的事件驅(qū)動驅(qū)動服務(wù)器資源競爭:

          之后呢,可以看做是并行的了:

          Fastsocket沒有重復(fù)發(fā)明輪子,在SO_REUSEPORT基礎(chǔ)上進行進一步的優(yōu)化等。

          嗯,后面準(zhǔn)備寫一個動態(tài)鏈接庫小程序,打算讓以前的沒有硬編碼SO_REUSEPORT的程序也能夠在Linux kernel >= 3.9系統(tǒng)上享受真正的端口重用的新特性的支持。

          Fastsocket架構(gòu)圖

          Image

          下面按照其架構(gòu)圖所示內(nèi)核層面從上到下一一列出。

          虛擬文件系統(tǒng)VFS的改進

          因為Linux Kernel VFS的同步損耗嚴(yán)重

          • VFS對文件節(jié)點Inode和目錄Dentry有同步需求
          • 但SOCKET只需要在內(nèi)存中存在即可,非嚴(yán)格意義上文件系統(tǒng),其不需要路徑,不需要為Inode和Dentry加鎖
          • 代碼層面略過不必須的常規(guī)鎖,但又保持了足夠的兼容性

          提交記錄:

          a209dfc vfs: dont chain pipe/anon/socket on superblock s_inodes list
          4b93688 fs: improve scalability of pseudo filesystems
          

          對VFS的改進,在所提升的性能中占有超過60%的比例,效果非常明顯:

          Local Listen Table

          對于多核多接收隊列來說,linux原生的協(xié)議棧只能listen在一個socket上面,并且所有完成三次握手還沒來得及被應(yīng)用accept的套接字都會放入其附帶的accept隊列中,accept系統(tǒng)調(diào)用必須串行的從隊列取出,當(dāng)并發(fā)量較大時多核競爭,這將成為性能瓶頸,影響建立連接處理速度。

          Local Listen Table,fastsocket為每一個CPU核克隆監(jiān)聽套接字,并保存到其本地表中,CPU核之間不會存在accept的競爭關(guān)系。下面為引用描述內(nèi)容:

          • 每個core有一個listen socket table。應(yīng)用程序建立連接的時候,執(zhí)行過程會調(diào)用local_listen()函數(shù),有兩個參數(shù),一個是socket FD,一個是core number. new socket從原始的listen socket(global)拷貝到per-core local socket table. 這些對于應(yīng)用程序來說都是透明的,提供給應(yīng)用程序的socketFD是抽象過的,隱藏了底層的實現(xiàn)。
          • 當(dāng)一個TCP SYN到達本機,kernel首先去local listen table中找匹配的listen socket,如果找到,就通過網(wǎng)卡RSS傳遞這個socket到一個core,否則就去global listen table中找。
          • 容錯方面,當(dāng)進程崩潰的話,local listen socket會被關(guān)閉,進入的連接將會被引導(dǎo)到global Listen socket, 這樣的話,別的process可以處理這些連接。由于local listen socket和global listen socket共享FD,所以kernel將會把新的connet通知到相應(yīng)的process。
          • 如果應(yīng)用程序進程使用accept()系統(tǒng)調(diào)用,那么處理過程是首先去global listen table中查找和操作(因為是讀操作,沒有使用鎖),如果沒有找到,那么去core的local table中查找。如果找到,就返回給應(yīng)用程序。由于listen的時候把socket綁定到了一個core,所以查找的時候也去這個core的local table中查找。
          • epoll兼容性,如果應(yīng)用程序使用epoll_ctl()系統(tǒng)調(diào)用,來把一個listen socket添加到Epoll set中,那么local的listen socket和global的listen socket都被epoll監(jiān)控。事件發(fā)生的時候,epoll_wait()系統(tǒng)調(diào)用會返回listen socket,accept()系統(tǒng)調(diào)用就會處理這個socket。這樣就保證了epoll實現(xiàn)的兼容性。

          使用流程圖概括上面所述:

          Image(9)

          Local Established Table

          Linux內(nèi)核使用一個全局的hash表以及鎖操作來維護establised sockets(被用來跟蹤連接的sockets)。Fastsocket 想法是把全局table分散到per-Core table,當(dāng)一個core需要訪問socket的時候,只在隸屬于自己的table中搜索,因此不需要鎖操縱,也不存在資源競爭。由fastsocket建立的socket本地local established table中,其他的regular sockets保存在global的table中。core首先去自己的local table中查找(不需要鎖),然后去global中查找。

          Image(10)

          Receive Flow Deliver

          默認(rèn)情況下,應(yīng)用程序主動發(fā)包的時候,發(fā)出去的包是通過正在執(zhí)行本進程的那個CPU 核(系統(tǒng)分配的)來完成的;而接收數(shù)據(jù)包的時CPU 核是由前面提到的RSS或RPS來傳遞。這樣一來,連接可能由不同的兩個CPU核來完成。連接應(yīng)該在本地化處理。RFS和Intel網(wǎng)卡的FlowDirector可以從軟件和硬件上緩解這種情況,但是不完備。

          RFD(Receive Flow Deliver)主要的思想是CPU核數(shù)主動發(fā)起連接的時候可以把CPU core的標(biāo)識和連接的source port編碼到一起。CPU cores和ports的關(guān)系由一個關(guān)系集合來決定【cores,ports】, 對于一個port,有唯一的一個core與之對應(yīng)。當(dāng)一個core來建立connection的時候,RFD隨機選擇一個跟當(dāng)前core匹配的port。接收包的時候,RFD負(fù)責(zé)決定這個包應(yīng)該讓哪一個core來處理,如果當(dāng)前core不是被選中的cpu core,那么就deliver到選中的cpu core。

          Image

          一般來說,RFD對代理程序收益比較大,單純的WEB服務(wù)器可以選擇禁用。

          小結(jié)

          以上參考了大量的外部資料進行整理而成,進而可以獲得一個較為整體的Fastsocket內(nèi)核架構(gòu)印象。

          Fastsocket的努力,在單個TCP連接的管理從網(wǎng)卡觸發(fā)的硬中斷、軟中斷、三次握手、數(shù)據(jù)傳輸、四次揮手等完整的過程在完整在一個CPU核上進行處理,從而實現(xiàn)了每一個CPU核心TCP資源本地化,這樣為多核水平擴展打好了基礎(chǔ),減少全局資源競爭,平行化處理連接,同時降低文件鎖的副作用,做到了極為高效的短連接處理方案,不得不贊啊。

          引用資料:

          posted on 2015-02-04 14:22 nieyong 閱讀(4670) 評論(1)  編輯  收藏 所屬分類: Socket

          評論

          # re: Fastsocket學(xué)習(xí)筆記之內(nèi)核篇 2015-02-06 09:20 京山游俠

          頂。  回復(fù)  更多評論   

          公告

          所有文章皆為原創(chuàng),若轉(zhuǎn)載請標(biāo)明出處,謝謝~

          新浪微博,歡迎關(guān)注:

          導(dǎo)航

          <2015年2月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          1234567

          統(tǒng)計

          常用鏈接

          留言簿(58)

          隨筆分類(130)

          隨筆檔案(151)

          個人收藏

          最新隨筆

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 甘孜| 通化市| 江西省| 滦南县| 陕西省| 红安县| 班玛县| 呼伦贝尔市| 广灵县| 建瓯市| 惠东县| 纳雍县| 永昌县| 海原县| 崇文区| 翼城县| 满洲里市| 开封县| 丰县| 石狮市| 黑山县| 翼城县| 营山县| 梁平县| 竹溪县| 治县。| 怀来县| 灵武市| 平度市| 林甸县| 布尔津县| 织金县| 佳木斯市| 黄陵县| 通榆县| 成武县| 大渡口区| 海淀区| 外汇| 无棣县| 监利县|