當前位置:
首頁 > 知識 > Linux 最新SO_REUSEPORT特性

Linux 最新SO_REUSEPORT特性

1、前言

昨天總結了一下Linux下網路編程「驚群」現象,給出Nginx處理驚群的方法,使用互斥鎖。為例發揮多核的優勢,目前常見的網路編程模型就是多進程或多線程,根據accpet的位置,分為如下場景:

(1)單進程或線程創建socket,並進行listen和accept,接收到連接後創建進程和線程處理連接

(2)單進程或線程創建socket,並進行listen,預先創建好多個工作進程或線程accept在同一個伺服器套接字、

Linux 最新SO_REUSEPORT特性

Linux 最新SO_REUSEPORT特性

這兩種模型解充分發揮了多核CPU的優勢,雖然可以做到線程和CPU核綁定,但都會存在:

  • 單一listener工作進程胡線程在高速的連接接入處理時會成為瓶頸
  • 多個線程之間競爭獲取服務套接字
  • 緩存行跳躍
  • 很難做到CPU之間的負載均衡
  • 隨著核數的擴展,性能並沒有隨著提升

Linux kernel 3.9帶來了SO_REUSEPORT特性,可以解決以上大部分問題。

2、SO_REUSEPORT解決了什麼問題

SO_REUSEPORT支持多個進程或者線程綁定到同一埠,提高伺服器程序的性能,解決的問題:

  • 允許多個套接字 bind/listen 同一個TCP/UDP埠
    • 每一個線程擁有自己的伺服器套接字
    • 在伺服器套接字上沒有了鎖的競爭
  • 內核層面實現負載均衡
  • 安全層面,監聽同一個埠的套接字只能位於同一個用戶下面

其核心的實現主要有三點:

  • 擴展 socket option,增加 SO_REUSEPORT 選項,用來設置 reuseport。
  • 修改 bind 系統調用實現,以便支持可以綁定到相同的 IP 和埠
  • 修改處理新建連接的實現,查找 listener 的時候,能夠支持在監聽相同 IP 和埠的多個 sock 之間均衡選擇。

有了SO_RESUEPORT後,每個進程可以自己創建socket、bind、listen、accept相同的地址和埠,各自是獨立平等的。讓多進程監聽同一個埠,各個進程中accept socket fd不一樣,有新連接建立時,內核只會喚醒一個進程來accept,並且保證喚醒的均衡性。

3、測試代碼

1 include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13
14 #define IP "127.0.0.1"
15 #define PORT 8888
16 #define WORKER 4
17 #define MAXLINE 4096
18
19 int worker(int i)
20 {
21 struct sockaddr_in address;
22 bzero(&address, sizeof(address));
23 address.sin_family = AF_INET;
24 inet_pton( AF_INET, IP, &address.sin_addr);
25 address.sin_port = htons(PORT);
26
27 int listenfd = socket(PF_INET, SOCK_STREAM, 0);
28 assert(listenfd >= 0);
29
30 int val =1;
31 /*set SO_REUSEPORT*/
32 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val))<0) { 33 perror("setsockopt"); 34 } 35 int ret = bind(listenfd, (struct sockaddr*)&address, sizeof(address)); 36 assert(ret != -1); 37 38 ret = listen(listenfd, 5); 39 assert(ret != -1); 40 while (1) { 41 printf("I am worker %d, begin to accept connection. ", i); 42 struct sockaddr_in client_addr; 43 socklen_t client_addrlen = sizeof( client_addr ); 44 int connfd = accept( listenfd, ( struct sockaddr* )&client_addr, &client_addrlen ); 45 if (connfd != -1) { 46 printf("worker %d accept a connection success. ip:%s, prot:%d ", i, inet_ntoa(client_addr.sin_addr), client_addr.sin_port); 47 } else { 48 printf("worker %d accept a connection failed,error:%s", i, strerror(errno)); 49 } 50 char buffer[MAXLINE]; 51 int nbytes = read(connfd, buffer, MAXLINE); 52 printf("read from client is:%s ", buffer); 53 write(connfd, buffer, nbytes); 54 close(connfd); 55 } 56 return 0; 57 } 58 59 int main 60 { 61 int i = 0; 62 for (i = 0; i < WORKER; i++) { 63 printf("Create worker %d ", i); 64 pid_t pid = fork; 65 /*child process */ 66 if (pid == 0) { 67 worker(i); 68 } 69 if (pid < 0) { 70 printf("fork error"); 71 } 72 } 73 /*wait child process*/ 74 while (wait(NULL) != 0) 75 ; 76 if (errno == ECHILD) { 77 fprintf(stderr, "wait error:%s ", strerror(errno)); 78 } 79 return 0; 80 }

我的測試機器內核版本為:

測試結果如下所示:

Linux 最新SO_REUSEPORT特性

Linux 最新SO_REUSEPORT特性

從結果可以看出,四個進程監聽相同的IP和port。

4、參考資料

http://lists.dragonflybsd.org/pipermail/users/2013-July/053632.html

http://www.blogjava.net/yongboy/archive/2015/02/12/422893.html

http://m.blog.chinaunix.net/uid-10167808-id-3807060.html

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 達人科技 的精彩文章:

Javascript 「繼承」
使用CoApp創建NuGet C++靜態庫包
大話Python正則表達式

TAG:達人科技 |

您可能感興趣

CentOS Linux 7和6用戶接收Intel和AMD CPU的新微碼更新
如何在 Linux 中安裝微軟的 .NET Core SDK
整理-LinuxVPS TCP加速
RNDA已發但Vega還要繼續:AMD提交新Vega GPU的Linux驅動
藍色巨人為IBM i、AIX、HANA以及Linux提供POWER9增強型伺服器
ARM推出Mbed Linux OS
在 Linux 上檢測 IDE/SATA SSD 硬碟的傳輸速度
賦能軟體定義 SUSE Linux Enterprise 15要做IT轉型的「橋樑」
美高森美和SiFive推出HiFive Unleashed擴展板助力Linux軟體和固件開發人員首次構建RISC-V PC
Chrome OS 更新新版本可讓Linux訪問USB連接的Android設備
RISC-V的Linux內核將會支持HiFive Unleashed開發板
Linux部署Nginx+Mysql+PHP+PHPMyAdmin4環境
SUSE Linux Enterprise 15 SP1 發布
SUSE Linux以25 億美元賣給EQT Partners
追月,Linux雲伺服器編譯安裝最新Apache、PHP和MySQL
玩轉SELINUX
Linux之組建VPS
經典Wind95系統變APP,可在Windows、macOS、Linux安裝使用
Linux查看Nginx、Apache、MySQL、PHP的編譯參數
常見的操作系統介紹-Windows,UNIX,Linux,Mac OS?