fastsocket優化網絡性能原理

fastsocket是一個fastos的一個網絡方面的優化,由新浪開源。fastsocket主要優化內核中的accept因爲鎖而導致的串行,對於短連接會極大的提高其性能,cpu核越多性能提升越明顯。基於內核模塊和一個動態鏈接庫,對於某些應用程序不需修改就可使用。但是並非所有應用都能通過fastsocket獲得性能提升。 fastsocket比較適用於一下場景:

Ø  系統至少不少於8個cpu

Ø  系統的很大一部分開銷用於處理網絡軟中斷以及socket相關係統調用

Ø  tcp短連接很多

Ø  應用使用了epool處理網絡io

Ø  應用使用了多進程接收連接

計劃增加特性:(改善長連接的性能)

Ø  direct-tcp:接收數據跳過路由處理

Ø  每一個核維護一個skb pool

Ø  投遞packet到應用運行的核上,類似於rfs,(聲稱更加精確)

Ø  位rps增加用戶定義接口

這裏特別說明的是,應用必須是多進程accept連接進行處理,並且每個進程採用epoll的方式才能通過fastsocket獲得性能提升。

 

fastsocket主要由一個內核模塊和一個用戶態動態鏈接庫,通過LD_PRELOAD攔截系統調用,經過libfsocket.so處理後,採用ioctl的形式和fastsocket內核模塊進行通信,內核模塊進行實際的優化工作。

fastsocket環境搭建

目前fastsocket只在2.6.x版本上實現,高版本需要移植才能使用。

kernel version = 2.6.x

 fastsocket安裝

下載fastsocket項目源代碼,包括內核和用戶態部分代碼。

git clone https://github.com/fastos/fastsocket.git

       代碼目錄介紹:

Ø  kernel :fastsocket優化定製過的內核

Ø  module :fastsocket內核模塊代碼,真實代碼在kernel的net下

Ø  library :fastsocket用戶態庫代碼

Ø  scripts :用於系統配置或者網卡配置的腳本

Ø  demo :fastsocket示範用例

家下來編譯fastsocket內核,編譯之前檢查內核選項的fastsocket相關選項是否配置:

>fastsocket/kernel

>make defconfig

>make

>make modules_install

>make install

編譯用戶態的庫

>cd library

>make

 

 

fastsocket配置

 

enable_listen_spawn

       使能該選項將會是連接本地化,對於多核多接收隊列來說,linux原生的協議棧只能listen在一個socket上面,並且所有完成三次握手還沒來得及被應用accept的套接字都會放入其附帶的accept隊列中,accept系統調用必須串行的從隊列取出,當併發量較大時這將成爲性能瓶頸。fastsocket將會通過copy listen socket在每個cpu上建立一個local cpu的listen socket,這樣accept隊列將會是local cpu的,將會大大改善accept性能,縮短連接建立的時間。事實上,如果設置了backlog,協議棧的accept數量將會受到限制,由於accept的串行將會導致大量連接不能建立,此項措施可以大大改善這個狀況。(事實上2014 nsdi論文mtcp也提到了相關的優化措施)。應用將會綁定到同一個cpu core上。

enable_listen_spawn=0

enable_listen_spawn=1

enable_listen_spawn=2 (default)

0:完全禁止這個特性;1:需要程序自己綁定到cpu核上;2:程序允許fastsocket模塊進行cpu的綁定。

enable_fast_epoll

       使能該選項fastsocket將會緩存file結構到epoll的映射關係,僅針對fastsocket的socket句柄,從而避免epoll對自身維護的tree進行查找帶來的消耗,但這要求socket fd必須只關聯了一個epoll實例,否則不要設置這個選項。

enable_fast_epoll=0

enable_fast_epoll=1 (default)

0:禁止特性;1:開啓特性。

 

enable_receive_flow_deliver

使能該選項,建立連接的時候其建立該連接的cpu id將會封裝到連接的port端口中,數據包到達時將會解析出cpu id並將包投遞到該cpu上,配合上面的listen local,將會是一個連接建立,中斷處理和數據接受都發生在同一個核上。該特性比較適合與長連接應用,同時如果啓用了rps,rps將會失效。(如果長連接的數據很不均衡,將會造成cpu負載不均衡)。

enable_receive_flow=0 (default)

enable_receive_flow=1

0:禁止特性;1:開啓特性。

fastsokcet使用

LD_PRELOAD=a/libfsocket.so program

a代表libfsocket.so的目錄,program代表需要運行的程序。

 

4. 

       首先分析下linux kernel 3.9之前的tcp常用api的實現,這裏涉及到google的reuse port的一個patch,這個在3.9內核之前是沒有的,由於fastsocket是基於2.6.32內核的,所以這裏先大概描述下3.9內核之前tcp相關的實現。

上圖大概描述了老內核的tcp socket的實現,bind系統調用會將socket和port進行綁定,並加入全局tcp_hashinfo的bhash中,所有bind調用都會查詢這個hash鏈表,如果port被佔用,很顯然老的內核會導致bind失敗。listen則是根據用戶設置的隊列大小預先爲tcp連接分配內存空間。也就是說,一個應用在同一個port上只能listen一次,那麼也就只有一個隊列來保存已經建立的連接。根據nginx的實現,在listen之後會fork處多個worker,每個worker會繼承listen的socket,然後每個worker會創建一個epoll fd,並將listen fd和accept的新連接的fd加入epoll fd。但是一旦新的連接到來,多個worker也只能排隊接收連接進行處理。對於大量的短連接,accept顯然成爲了一個瓶頸。

       fastsocket的實現建立在google的reuse port的patch之上,也就是說同一個user id,net namespace,ip,port可以被多個進程listen,多個進程可以同時listen在同一個port上,當然前提是滿足前面提到的條件。fastsocket在用戶態實現了一個動態鏈接庫libfsocket.so,socket、bind、listen等系統調用在啓用fastsocket的時候會被攔截並進入這個鏈接庫進行處理,對於listen系統調用,fastsocket會記錄下這個fd,當應用通過epoll將這個fd加入到epoll fdset中時,libfsocket.so會通過ioctl爲該進程clone listen fd關聯的socket、sock、file的系統資源,並將clone的socket再次調用bind和listen,這些都是在內核態實現的,bind系統調用檢測到另外一個進程綁定到已經被綁定的port時,會進行相關檢查,如果通過檢查那麼這個sock將會被記錄到port相關聯的一個鏈表中,通過該鏈表可以知道所有bind同一個port的sock,而sock是關聯到fd的,進程則持有fd,那麼所有的資源就已經關聯到一起了,而新的進程再次調用listen系統調用的時候,內核會再次爲其關聯的sock分配accept隊列。那麼多個進程也就擁有了多個accept 隊列,爲了避免cpu cache miss導致的性能損失,fastsocket提供將每個listen和accept的進程綁定到用戶指定的cpu core上,如果用戶未指定,fastsocket將會爲該進程默認綁定一個空閒的cpu 核。fastsocket的實現原理圖如下所示。

上面的實現很明顯對於短連接的性能有很大的提高,性能的提升可以預估和cpu的個數有關,cpu越多,性能提升將會越大。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章