當(dāng)前位置:首頁 > IT技術(shù) > 其他 > 正文

    I/O模型剖析
    2022-04-25 23:07:21

    1.服務(wù)端處理網(wǎng)絡(luò)請求過程

    I/O模型剖析_I/O模型剖析

    IO分為:

    網(wǎng)絡(luò)IO:本質(zhì)是socket文件讀取;上圖中紅線部分

    磁盤IO:上圖中藍(lán)線部分

    由上圖可知:IO都分為了兩個階段

    1.將數(shù)據(jù)從文件先加載至內(nèi)核內(nèi)存空間(緩沖區(qū))--時間長
    2.將數(shù)據(jù)從內(nèi)核緩沖區(qū)復(fù)制到用戶空間的進(jìn)程的內(nèi)存中--時間短

    服務(wù)端處理網(wǎng)絡(luò)請求的過程

    1.客戶端發(fā)起請求,數(shù)據(jù)發(fā)送到網(wǎng)卡
    2.將網(wǎng)卡中數(shù)據(jù)通過DMA機(jī)制復(fù)制到內(nèi)核緩沖區(qū)
    3.內(nèi)核緩沖區(qū)復(fù)制到用戶空間(比如要:GET index.html)
    -------------------
    4.web服務(wù)器收到請求數(shù)據(jù),因?yàn)閼?yīng)用程序無法與硬件打交道,所以向內(nèi)核空間發(fā)起系統(tǒng)調(diào)用
    5.內(nèi)核空間收到信息,cpu發(fā)出指令,讓DMA設(shè)備去磁盤獲取index.html,并拷貝到內(nèi)核緩沖區(qū)
    6.內(nèi)核緩沖區(qū)再復(fù)制到用戶空間
    -------------------
    7.web服務(wù)器收到數(shù)據(jù),然后構(gòu)建響應(yīng)報(bào)文,再發(fā)送給內(nèi)核空間的socket buffer
    8.socket buffer 在發(fā)送給網(wǎng)卡
    9.通過網(wǎng)卡把響應(yīng)報(bào)文發(fā)送給客戶端

    2.什么是DMA

    DMA:直接內(nèi)存訪問

    I/O模型剖析_I/O模型剖析_02

    PIO 程序的輸入輸出模型,--所有操作都需要CPU參與
    DMA 直接內(nèi)存訪問;只需要cpu發(fā)送指令,讓DMA設(shè)備去把磁盤數(shù)據(jù)拷貝到內(nèi)存,降低CPU的使用率

    3.IO模型

    同步,異步,阻塞,非阻塞的理解

    I/O模型剖析_I/O模型剖析_03

    比如上圖:A是領(lǐng)導(dǎo)  B是員工
    現(xiàn)在A讓B去做一件事情

    同步就是:領(lǐng)導(dǎo)自己去詢問事情是否做完
    異步就是:員工主動告知領(lǐng)導(dǎo)事情的進(jìn)度

    阻塞就是:事情非常緊急需要馬上解決,領(lǐng)導(dǎo)必須盯著員工把事情做完,不能干其他的
    非阻塞:領(lǐng)導(dǎo)在員工做事情時,可以去喝喝茶,打打高爾夫...等等

    A對應(yīng):應(yīng)用程序
    B對應(yīng):內(nèi)核
    只有讓內(nèi)核多做事情,應(yīng)用程序少做,這樣才能實(shí)現(xiàn)高并發(fā)

    衍生出

    同步阻塞,同步非阻塞,異步阻塞,異步非阻塞

    場景:用燒水壺?zé)?br/>
    同步阻塞就是:買的燒水壺是無聲的,為了把水燒開,并且不能讓水噴出來,就只能守著燒

    同步非阻塞:買的燒水壺也是無聲的,只需要把水燒開就行,不管開水會不會噴出,所以我就可以在燒水時,去看看電視
    偶爾去看看水是否燒開就行

    異步阻塞:這次買的燒水壺可以語音提示,燒開了會提醒,如果我此時還守著,不是有病嘛,所以這沒意義

    異步非阻塞:水燒開自動提醒我,在燒水時我可以開心看電視

    4.五中IO模型

    阻塞型、非阻塞型、復(fù)用型、信號驅(qū)動型、異步

    4.1.阻塞型

    I/O模型剖析_I/O模型剖析_04

    理解場景:釣魚

    去釣魚,那人必須守著
    數(shù)據(jù)準(zhǔn)備好:就好比魚兒上鉤,這個過程是很漫長的
    復(fù)制完成:好比當(dāng)魚兒上鉤,把魚兒放到桶里,這個過程很快

    在釣魚的過程中,為了不讓魚兒跑掉,你必須一直守著,不能干其他的;所以一直是阻塞的

    4.2.非阻塞型

    I/O模型剖析_I/O模型剖析_05

    理解場景: 釣魚,釣魚旁邊有個麻將館

    釣魚時,把魚竿搞好,就去麻將館打麻將了...
    打一局,我就去看看魚兒上鉤沒有...
    當(dāng)魚兒上鉤了,這個時候我必須在場把魚兒放在桶里

    在魚兒上鉤過程中,我都跑去打麻將了,只是偶爾去看看魚兒是否上鉤,也只有把魚放在桶里這階段我在場,所以
    只有這段時間是阻塞的

    4.3.復(fù)用型

    I/O模型剖析_I/O模型剖析_06

    理解場景:我雇了一只貓去守著釣魚,而且這次拿了很多釣竿

    讓貓?jiān)诤舆吺刂?,但是呢,我又怕貓偷吃,所以我也只能盯著貓不能去打麻將了,這階段我是阻塞的
    當(dāng)有釣竿魚上鉤了,貓就叫我,然后我就過去把魚放在桶里,所以我從頭到尾一直都是阻塞的....

    4.4.信號驅(qū)動型

    I/O模型剖析_I/O模型剖析_07

    理解場景:我買了一個帶語音提示的魚竿

    這次,我把魚竿搞好,我也依然去旁邊的麻將館打麻將了,
    當(dāng)魚兒上鉤了,就語音提示我,主人,主人,魚上鉤了,然后我就去把魚兒放在桶里

    只有把魚放在桶里,我需要去河邊,這段時間我是阻塞的

    4.5.異步

    I/O模型剖析_I/O模型剖析_08

    理解場景:由于前幾次都是空軍,這次我就聘請了一個釣魚達(dá)人去釣

    釣魚達(dá)人在釣魚,我就去打麻將..
    我麻將打完了,釣魚達(dá)人,就把魚兒給我了

    5.五種I/O模型比較

    I/O模型剖析_I/O模型剖析_09

    阻塞型:一直都阻塞
    非阻塞:只有魚兒放桶里是阻塞
    復(fù)用型:也是一直阻塞
    信號驅(qū)動:只有魚兒放桶里是阻塞
    異步:完全不阻塞

    6.模型實(shí)現(xiàn)的方式

    Select:   #Linux實(shí)現(xiàn)         對應(yīng)I/O復(fù)用模型      BSD4.2最早實(shí)現(xiàn),POSIX標(biāo)準(zhǔn),一般操作系統(tǒng)均有實(shí)現(xiàn)
    Poll: #Linux實(shí)現(xiàn), 對應(yīng)I/O復(fù)用模型 System V unix最早實(shí)現(xiàn)
    Epoll: #Linux特有, 對應(yīng)I/O復(fù)用模型 具有信號驅(qū)動I/O模型的某些特性

    Kqueue: #FreeBSD實(shí)現(xiàn), 對應(yīng)I/O復(fù)用模型 具有信號驅(qū)動I/O模型某些特性
    /dev/poll:#SUN的Solaris實(shí)現(xiàn) 對應(yīng)I/O復(fù)用模型 具有信號驅(qū)動I/O模型的某些特性
    Iocp #Windows實(shí)現(xiàn), 對應(yīng)第5種(異步I/O)模型

    7.select/poll/epoll

    I/O模型剖析_I/O模型剖析_10

    I/O模型剖析_I/O模型剖析_11

    7.1.select

    Select:POSIX所規(guī)定,目前幾乎在所有的平臺上支持,其良好跨平臺支持也是它的一個優(yōu)點(diǎn),本質(zhì)上是通過設(shè)置或
    者檢查存放fd標(biāo)志位的數(shù)據(jù)結(jié)構(gòu)來進(jìn)行下一步處理

    #缺點(diǎn)
    1)單個進(jìn)程能夠監(jiān)視的文件描述符的數(shù)量存在最大限制,在Linux上一般為1024,可以通過修改宏定義FD_SETSIZE,
    再重新編譯內(nèi)核實(shí)現(xiàn),但是這樣也會造成效率的降低
    2)單個進(jìn)程可監(jiān)視的fd數(shù)量被限制,默認(rèn)是1024,修改此值需要重新編譯內(nèi)核
    3)對socket是線性掃描,即采用輪詢的方法,效率較低
    4)select 采取了內(nèi)存拷貝方法來實(shí)現(xiàn)內(nèi)核將 FD 消息通知給用戶空間,這樣一個用來存放大量fd的數(shù)據(jù)結(jié)構(gòu),
    這樣會使得用戶空間和內(nèi)核空間在傳遞該結(jié)構(gòu)時復(fù)制開銷大

    7.2.poll

    1)本質(zhì)上和select沒有區(qū)別,它將用戶傳入的數(shù)組拷貝到內(nèi)核空間,然后查詢每個fd對應(yīng)的設(shè)備狀態(tài)
    2)其沒有最大連接數(shù)的限制,原因是它是基于鏈表來存儲的
    3)大量的fd的數(shù)組被整體復(fù)制于用戶態(tài)和內(nèi)核地址空間之間,而不管這樣的復(fù)制是不是有意義
    4)poll特點(diǎn)是"水平觸發(fā)",如果報(bào)告了fd后,沒有被處理,那么下次poll時會再次報(bào)告該fd

    7.3.epoll

    epoll:在Linux 2.6內(nèi)核中提出的select和poll的增強(qiáng)版本
    支持水平觸發(fā)LT和邊緣觸發(fā)ET,最大的特點(diǎn)在于邊緣觸發(fā),它只告訴進(jìn)程哪些fd剛剛變?yōu)榫托钁B(tài),并且只會通知一次
    使用"事件"的就緒通知方式,通過epoll_ctl注冊fd,一旦該fd就緒,內(nèi)核就會采用類似callback的回調(diào)機(jī)制來激
    活該fd,epoll_wait便可以收到通知

    #優(yōu)點(diǎn):
    1)沒有最大并發(fā)連接的限制:能打開的FD的上限遠(yuǎn)大于1024(1G的內(nèi)存能監(jiān)聽約10萬個端口),具體查看
    /proc/sys/fs/file-max,此值和系統(tǒng)內(nèi)存大小相關(guān)
    2)效率提升:非輪詢的方式,不會隨著FD數(shù)目的增加而效率下降;只有活躍可用的FD才會調(diào)用callback函數(shù),
    即epoll最大的優(yōu)點(diǎn)就在于它只管理"活躍"的連接,而跟連接總數(shù)無關(guān)
    3)內(nèi)存拷貝,利用mmap(Memory Mapping)加速與內(nèi)核空間的消息傳遞;即epoll使用mmap減少復(fù)制開銷

    邊緣觸發(fā):只通知一次

    8.什么是零拷貝

    傳統(tǒng)Linux中 I/O 的問題

    傳統(tǒng)的Linux系統(tǒng)的標(biāo)準(zhǔn) I/O 接口(read、write)是基于數(shù)據(jù)拷貝的,也就是數(shù)據(jù)都是 copy_to_user 或者
    copy_from_user,這樣做的好處是,通過中間緩存的機(jī)制,減少磁盤 I/O 的操作,
    但是壞處也很明顯,大量數(shù)據(jù)的拷貝,用戶態(tài)和內(nèi)核態(tài)的頻繁切換,會消耗大量的 CPU 資源,嚴(yán)重影響數(shù)據(jù)傳輸?shù)?br/>性能
    統(tǒng)計(jì)表明,在Linux協(xié)議棧中,數(shù)據(jù)包在內(nèi)核態(tài)和用戶態(tài)之間的拷貝所用的時間甚至占到了數(shù)據(jù)包整個處理流
    程時間的57.1%
    零拷貝就是上述問題的一個解決方案,盡量避免拷貝操作來緩解 CPU 的壓力。
    零拷貝并沒有真正做到"0"拷貝,它更多是一種思想,很多的零拷貝技術(shù)都是基于這個思想去做的優(yōu)化

    8.1.原始數(shù)據(jù)拷貝操作

    I/O模型剖析_I/O模型剖析_12

    8.2.MMAP:Memory Mapping

    I/O模型剖析_I/O模型剖析_13

    8.3.SENDFILE

    I/O模型剖析_I/O模型剖析_14

    8.4.DMA 輔助的 SENDFILE

    I/O模型剖析_I/O模型剖析_15

    9.Httpd MPM

    HTTP中的三種請求處理模式(MPM)的區(qū)別

    (1)prefork(預(yù)派生模式):多進(jìn)程I/o模型,每個進(jìn)程相應(yīng)一個請求  #-->>進(jìn)程模型,兩級結(jié)構(gòu)
    主進(jìn)程--子進(jìn)程--線程--請求
    |--子進(jìn)程--線程--請求
    |--子進(jìn)程--線程--請求
    優(yōu)點(diǎn):穩(wěn)定
    缺點(diǎn):慢,占用資源(內(nèi)存),不適用于高并發(fā)場景
    使用select 模型,最大并發(fā)1024


    (2)worker:復(fù)用的多進(jìn)程I/O模型,多進(jìn)程多線程 #-->>線程模型,三級結(jié)構(gòu)
    主進(jìn)程--子進(jìn)程--線程--請求
    | --線程--請求
    | --線程--請求
    |--子進(jìn)程--線程--請求
    | --線程--請求
    | --線程--請求
    優(yōu)點(diǎn):相比prefork,占用內(nèi)存較少,可以同時處理更多的請求
    缺點(diǎn):使用keep-alive的長連接方式,某個線程會一直被占據(jù),即使沒有傳輸數(shù)據(jù),也需要一直等待到超時才會被釋放。


    (3)event 事件驅(qū)動模型(epoll),增加了一個監(jiān)聽線程 #-->>線程模型,三級結(jié)構(gòu)
    監(jiān)聽線程:用于向工作線程分配任務(wù)并和客戶端保持會話連接,超時之后監(jiān)聽線程會刪除socket,工作線程只處理用戶請求,處理完之后將會話保持交于監(jiān)聽線程,自己去處理新的請求,不再負(fù)責(zé)會話保持
    主進(jìn)程--子進(jìn)程--監(jiān)聽線程--請求1 空請求不被分配 請求3
    | |--工作線程--請求1
    | |--工作線程--請求3
    | |--工作線程 處理完成請求,將keep-alived交給監(jiān)聽線程,自己開始等待處理新請求
    與worker進(jìn)程很像,最大的區(qū)別在于,它解決了keep-alive場景下,長期被占用的線程的資源浪費(fèi)問題
    優(yōu)點(diǎn):單線程響應(yīng)多請求,占據(jù)更少的內(nèi)存,高并發(fā)下表現(xiàn)更優(yōu)秀
    缺點(diǎn):沒有線程安全控制

    本文摘自 :https://blog.51cto.com/t

    開通會員,享受整站包年服務(wù)立即開通 >