1. 程式人生 > >高效能網路伺服器程式設計:為什麼linux下epoll是最好,Netty要比NIO.2好?

高效能網路伺服器程式設計:為什麼linux下epoll是最好,Netty要比NIO.2好?

  基本的IO程式設計過程(包括網路IO和檔案IO)是,開啟檔案描述符(windows是handler,java是stream或channel),多路捕獲(Multiplexe,即select和poll和epoll)IO可讀寫的狀態,而後可以讀寫的檔案描述符進行IO讀寫,由於IO裝置速度和CPU記憶體比速度會慢,為了更好的利用CPU和記憶體,會開多執行緒,每個執行緒讀寫一個檔案描述符。

  但C10K問題,讓我們意識到在超大數量的網路連線下,機器裝置和網路速度不再是瓶頸,瓶頸在於作業系統和IO應用程式的溝通協作的方式

      舉個例子,一萬個socket連線過來,傳統的IO程式設計模型要開萬個執行緒來應對,還要注意,socket會關閉開啟,一萬個執行緒要不斷的關閉執行緒重建執行緒,資源都浪費在這上面了,我們算建立一個執行緒耗1M記憶體,1萬個執行緒機器至少要10G記憶體,這在IA-32的機器架構下基本是不可能的(要開PAE),現在x64架構才有可能舒服點,要知道,這僅僅是粗略算的記憶體消耗。別的資源呢?

     所以,高效能的網路程式設計(即IO程式設計),第一,需要鬆綁IO連線和應用程式執行緒的對應關係,這就是非阻塞(nonblocking)、非同步(asynchronous)的要求的由來(構造一個執行緒池,epoll監控到有數的fd,把fd傳入執行緒池,由這些worker thread來讀寫io)。第二,需要高效能的OS對IO裝置可讀寫(資料來了)的通知方式:從level-triggered notification到edge-triggered notification,關於這個通知方式,我們稍後談。

    需要注意非同步,不等於AIO(asynchronous IO),linux的AIO和java的AIO都是實現非同步的一種方式,都是

,這個我們也接下來會談到。

    針對前面說的這兩點,我們看看select和poll的問題

  imageimage

    這兩個函式都在每次呼叫的時候要求我們把需要監控(看看有沒有資料)的檔案描述符,通過陣列傳遞進入核心,核心每次都要掃描這些檔案描述符,去理解它們,建立一個檔案描述符和IO對應的陣列(實際核心工作會有好點的實現方式,但可以這麼理解先),以便IO來的時候,通知這些檔案描述符,進而通知到程序裡等待的這些select、poll。當有一萬個檔案描述符要監控的時候呢(一萬個網路連線)?這個工作效率是很低的,資源要求卻很高。

  我們看epoll

  image

  image

  image

    epoll很巧妙,分為三個函式,第一個函式建立一個session類似的東西,第二函式告訴核心維持這個session,並把屬於session內的fd傳給核心,第三個函式epoll_wait是真正的監控多個檔案描述符函式,只需要告訴核心,我在等待哪個session,而session內的fd,核心早就分析過了,不再在每次epoll呼叫的時候分析,這就節省了核心大部分工作。這樣每次呼叫epoll,核心不再重新掃描fd陣列,因為我們維持了session。

    說道這裡,只有一個字,開源,贊,眾人拾柴火焰高,贊。

    epoll的效率還不僅僅體現在這裡,在核心通知方式上,也改進了,我們先看select和poll的通知方式,也就是level-triggered notification,核心在被DMA中斷,捕獲到IO裝置來資料後,本來只需要查詢這個資料屬於哪個檔案描述符,進而通知執行緒裡等待的函式即可,但是,select和poll要求核心在通知階段還要繼續再掃描一次剛才所建立的核心fd和io對應的那個陣列,因為應用程式可能沒有真正去讀上次通知有資料後的那些fd,應用程式上次沒讀,核心在這次select和poll呼叫的時候就得繼續通知,這個os和應用程式的溝通方式效率是低下的。只是方便程式設計而已(可以不去讀那個網路io,方正下次會繼續通知)。

    於是epoll設計了另外一種通知方式:edge-triggered notification,在這個模式下,io裝置來了資料,就只通知這些io裝置對應的fd,上次通知過的fd不再通知,核心不再掃描一大堆fd了。

    基於以上分析,我們可以看到epoll是專門針對大網路併發連線下的os和應用溝通協作上的一個設計,在linux下編網路伺服器,必然要採用這個,nginx、php的國產非同步框架swool、varnish,都是採用這個。

    注意還要開啟epoll的edge-triggered notification。而java的NIO和NIO.2都只是用了epoll,沒有開啟edge-triggered notification,所以不如JBoss的Netty。

    接下來我們談談AIO的問題,AIO希望的是,你select,poll,epoll都需要用一個函式去監控一大堆fd,那麼我AIO不需要了,你把fd告訴核心,你應用程式無需等待,核心會通過訊號等軟中斷告訴應用程式,資料來了,你直接讀了,所以,用了AIO可以廢棄select,poll,epoll。

    但linux的AIO的實現方式是核心和應用共享一片記憶體區域,應用通過檢測這個記憶體區域(避免呼叫nonblocking的read、write函式來測試是否來資料,因為即便呼叫nonblocking的read和write由於程序要切換使用者態和核心態,仍舊效率不高)來得知fd是否有資料,可是檢測記憶體區域畢竟不是實時的,你需要線上程裡構造一個監控記憶體的迴圈,設定sleep,總的效率不如epoll這樣的實時通知。所以,AIO是渣,適合低併發的IO操作。所以java7引入的NIO.2引入的AIO對高併發的網路IO設計程式來說,也是,只有Netty的epoll+edge-triggered notification最牛,能在linux讓應用和OS取得最高效率的溝通。

  注:非阻塞IO和非同步IO基本是一個意思,只是描述同一個東西的不同方面。

  In computer science, asynchronous I/O, or non-blocking I/O is a form of input/output processing that permits other processing to continue before thetransmission has finished.

相關推薦

高效能網路伺服器程式設計為什麼linuxepoll最好NettyNIO.2

  基本的IO程式設計過程(包括網路IO和檔案IO)是,開啟檔案描述符(windows是handler,java是stream或channel),多路捕獲(Multiplexe,即select和poll和epoll)IO可讀寫的狀態,而後可以讀寫的檔案描述符進行IO讀寫,由於IO裝置速度和CPU記憶體比速度會

高性能網絡服務器編程為什麽linuxepoll最好NettyNIO.2

系統 工作效率 lee socket 為我 handler 10g 函數 適合 基本的IO編程過程(包括網絡IO和文件IO)是,打開文件描述符(windows是handler,java是stream或channel),多路捕獲(Multiplexe,即select和poll

網路程式設計專案linux基於C/S架構的聊天室

一、專案要求: 1. 採用 Client/Server 架構  2. Client A 登陸聊天伺服器前,需要註冊自己的 ID 和密碼  3. 註冊成功後,Client A 就可以通過自己的 ID 和密碼登陸聊天伺服器  4. 多個 Client X 可以同時登陸聊天伺服器

Linux C程式設計之一Linuxc語言的開發環境

—恢復內容開始— 今天開始根據Linux C程式設計相關視訊的學習所做的筆記,希望能一直堅持下去。。。 1、開發環境的構成 編輯器:VI; 編譯器:選擇GNU C/C++編譯器gcc; 偵錯程式:應用廣泛的gdb; 函式庫:glibc ; 系統標頭檔案:glibc_header; 2、在安裝L

Caffe學習筆記1linux建立自己的資料庫訓練和測試caffe中已有網路

本文是基於薛開宇 《學習筆記3:基於自己的資料訓練和測試“caffeNet”》基礎上,從頭到尾把實驗跑了一遍~對該文中不清楚的地方做了更正和說明。 主要工作如下: 1、下載圖片建立資料庫 2、將圖片轉化為256*256的lmdb格式 3、計算影象均值 4、定義網路修改部分引

突破傳統Linux如何架設BT伺服器

傳統的檔案下載服務都是基於客戶機/伺服器模型,被下載的檔案放在伺服器上,使用者登入伺服器,將該檔案下載到本地。在檔案下載的過程中,被傳輸檔案的來源和目的端並不對等,伺服器只是單向地將檔案傳送給客戶端。        這種傳統軟體下載模式的缺點是顯而易見的,整個系統的瓶頸位於

網路學習 linux修改ip地址預設閘道器以及DNS ifconfig route

*修改IP地址 即時生效: ifconfig eth0 192.168.1.100  netmask 255.255.255.0 重啟生效: vim  /etc/sysconfig/network-scripts/ifcfg-eth0        --增加或者修改下面幾

linuxshell顯示-bash-4.1#不顯示路徑解決方法

所屬組 再次 修改 root 顯示 lin 解決 use .bashrc 幾個可能導致的原因: 1 用戶的家目錄所屬組被改為root,解決方法使用root執行cd /home/;chown username:username username 2 用戶的家目錄被修改,這個時

.Neter玩轉Linux系列之二Linux的文件目錄及文件目錄的權限

pac linux 在那 用戶 目錄結構 重要 bsp 樹狀 hub 一、Linux下的文件目錄 簡介:linux的文件系統是采用級層式的樹狀目錄結構,在此 結構中的最上層是根目錄“/”,然後在此目錄下再創建 其他的目錄。深刻理解linux文件目錄是

Linux用Jmeter做接口測試

接口 保存 ora cor tac 測試報告 cron 分享 添加 本地設計   首先在本地設計 Apache JMeter 測試計劃,大家可以參考《接口測試之 JMeter 初探》 ,這裏不再重復。   服務器配置   確保服務器已經安裝了JDK和Python。   在服

轉載Linux查看/修改系統時區、時間

div 系統 啟動 localtime ive hctosys red 亞洲 命令 一、查看和修改Linux的時區 1. 查看當前時區 命令 : "date -R" 2. 修改設置Linux服務器時區 方法 A 命令 : "tzselect" 方法 B 僅限於RedHat

視頻轉碼linuxffmpeg 實現視頻轉碼

視頻轉碼使用shell快速安裝視頻轉碼器 #!/bin/bash #1、保證系統可以連到外網,需要下載安裝包和依賴包 #2、依賴gcc編譯器 #3、測試命令:ffmpeg -i test.avi out.mp4 set -e ffmDir="/usr/myapp" ffmVer="ffmpeg-3.4.1

視頻轉碼 linux用mplayer做視頻轉碼

視頻轉碼視頻轉碼器mplayer安裝使用 #!/bin/bash #1、保證系統可以連到外網,需要下載安裝包和依賴包 set -e MPlayer="/usr/myapp" MPVer="MPlayer-1.3.0" mkdir $MPlayer -pv yum install wget gcc

自動化服務部署(一)Linux安裝JDK

evel pos 的人 lis jdk安裝 參考 8.0 根據 如何 自動化測試的主要目的是為了執行回歸測試。當然,為了模擬真實的用戶操作,一般都是在UAT或者生產環境進行回歸測試。 為了盡量避免內網和外網解析對測試結果的影響,一般將自動化測試服務部署在外網的服務器是比較

自動化服務部署(三)Linux安裝Git

ima yum lan 參考 lease 指令 mage sta shu Git是一個開源的分布式版本控制系統,可以有效、高速的處理從很小到非常大的項目版本管理,是目前使用範圍最廣的版本管理工具。 這篇博客,介紹下Linux下安裝Git的步驟,僅供參考,當然,還是yum安裝

轉載Linux解壓zip亂碼問題的解決(unzip)

方式 -h linu 文件名 inf etc java env 系統默認 https://blog.csdn.net/abyjun/article/details/48344379 在windows上壓縮的文件,是以系統默認編碼中文來壓縮文件。由於zip文件中沒有聲明其編碼

zabbixlinuxzabbix-agent的安裝

本人最近需要安裝zabbix-agent,所以就在網上查詢教程,後面發現大部分都是直接利用zabbix安裝包進行安裝,或者是利用wget來安裝,但是這樣不能聯網的機器就無法使用,下面是介紹我的安裝方法。 1.下載zabbix-agent的deb安裝包 2.直接利用dpkg命令來安

C++網路伺服器程式設計的學習路線

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

LIVE555學習1Linuxlive555的編譯及測試

以下為在linux下編譯和測試live555的全部過程。 文章目錄 1 原始碼下載 2 編譯 3 測試 1 原始碼下載 官網地址:http://www.live555.com/liveMedia/public/ 開啟後,選擇li

網路伺服器程式設計——完成埠

4.3.5完成埠模型(IOCP) 選擇模型是5種模型中效率最低的,而完成埠則是5種模型中效率最高的IO模型。 //完成埠TCP伺服器 #include <iostream> #include <winsock2.h> #include&