1.服務(wù)端處理網(wǎng)絡(luò)請(qǐng)求過(guò)程
IO分為:
網(wǎng)絡(luò)IO:本質(zhì)是socket文件讀取;上圖中紅線(xiàn)部分
磁盤(pán)IO:上圖中藍(lán)線(xiàn)部分
由上圖可知:IO都分為了兩個(gè)階段
1.將數(shù)據(jù)從文件先加載至內(nèi)核內(nèi)存空間(緩沖區(qū))--時(shí)間長(zhǎng)
2.將數(shù)據(jù)從內(nèi)核緩沖區(qū)復(fù)制到用戶(hù)空間的進(jìn)程的內(nèi)存中--時(shí)間短
服務(wù)端處理網(wǎng)絡(luò)請(qǐng)求的過(guò)程
1.客戶(hù)端發(fā)起請(qǐng)求,數(shù)據(jù)發(fā)送到網(wǎng)卡
2.將網(wǎng)卡中數(shù)據(jù)通過(guò)DMA機(jī)制復(fù)制到內(nèi)核緩沖區(qū)
3.內(nèi)核緩沖區(qū)復(fù)制到用戶(hù)空間(比如要:GET index.html)
-------------------
4.web服務(wù)器收到請(qǐng)求數(shù)據(jù),因?yàn)閼?yīng)用程序無(wú)法與硬件打交道,所以向內(nèi)核空間發(fā)起系統(tǒng)調(diào)用
5.內(nèi)核空間收到信息,cpu發(fā)出指令,讓DMA設(shè)備去磁盤(pán)獲取index.html,并拷貝到內(nèi)核緩沖區(qū)
6.內(nèi)核緩沖區(qū)再?gòu)?fù)制到用戶(hù)空間
-------------------
7.web服務(wù)器收到數(shù)據(jù),然后構(gòu)建響應(yīng)報(bào)文,再發(fā)送給內(nèi)核空間的socket buffer
8.socket buffer 在發(fā)送給網(wǎng)卡
9.通過(guò)網(wǎng)卡把響應(yīng)報(bào)文發(fā)送給客戶(hù)端
2.什么是DMA
DMA:直接內(nèi)存訪問(wèn)
PIO 程序的輸入輸出模型,--所有操作都需要CPU參與
DMA 直接內(nèi)存訪問(wèn);只需要cpu發(fā)送指令,讓DMA設(shè)備去把磁盤(pán)數(shù)據(jù)拷貝到內(nèi)存,降低CPU的使用率
3.IO模型
同步,異步,阻塞,非阻塞的理解
比如上圖:A是領(lǐng)導(dǎo) B是員工
現(xiàn)在A讓B去做一件事情
同步就是:領(lǐng)導(dǎo)自己去詢(xún)問(wèn)事情是否做完
異步就是:員工主動(dòng)告知領(lǐng)導(dǎo)事情的進(jìn)度
阻塞就是:事情非常緊急需要馬上解決,領(lǐng)導(dǎo)必須盯著員工把事情做完,不能干其他的
非阻塞:領(lǐng)導(dǎo)在員工做事情時(shí),可以去喝喝茶,打打高爾夫...等等
A對(duì)應(yīng):應(yīng)用程序
B對(duì)應(yīng):內(nèi)核
只有讓內(nèi)核多做事情,應(yīng)用程序少做,這樣才能實(shí)現(xiàn)高并發(fā)
衍生出
同步阻塞,同步非阻塞,異步阻塞,異步非阻塞
場(chǎng)景:用燒水壺?zé)?br/>
同步阻塞就是:買(mǎi)的燒水壺是無(wú)聲的,為了把水燒開(kāi),并且不能讓水噴出來(lái),就只能守著燒
同步非阻塞:買(mǎi)的燒水壺也是無(wú)聲的,只需要把水燒開(kāi)就行,不管開(kāi)水會(huì)不會(huì)噴出,所以我就可以在燒水時(shí),去看看電視
偶爾去看看水是否燒開(kāi)就行
異步阻塞:這次買(mǎi)的燒水壺可以語(yǔ)音提示,燒開(kāi)了會(huì)提醒,如果我此時(shí)還守著,不是有病嘛,所以這沒(méi)意義
異步非阻塞:水燒開(kāi)自動(dòng)提醒我,在燒水時(shí)我可以開(kāi)心看電視
4.五中IO模型
阻塞型、非阻塞型、復(fù)用型、信號(hào)驅(qū)動(dòng)型、異步
4.1.阻塞型
理解場(chǎng)景:釣魚(yú)
去釣魚(yú),那人必須守著
數(shù)據(jù)準(zhǔn)備好:就好比魚(yú)兒上鉤,這個(gè)過(guò)程是很漫長(zhǎng)的
復(fù)制完成:好比當(dāng)魚(yú)兒上鉤,把魚(yú)兒放到桶里,這個(gè)過(guò)程很快
在釣魚(yú)的過(guò)程中,為了不讓魚(yú)兒跑掉,你必須一直守著,不能干其他的;所以一直是阻塞的
4.2.非阻塞型
理解場(chǎng)景: 釣魚(yú),釣魚(yú)旁邊有個(gè)麻將館
釣魚(yú)時(shí),把魚(yú)竿搞好,就去麻將館打麻將了...
打一局,我就去看看魚(yú)兒上鉤沒(méi)有...
當(dāng)魚(yú)兒上鉤了,這個(gè)時(shí)候我必須在場(chǎng)把魚(yú)兒放在桶里
在魚(yú)兒上鉤過(guò)程中,我都跑去打麻將了,只是偶爾去看看魚(yú)兒是否上鉤,也只有把魚(yú)放在桶里這階段我在場(chǎng),所以
只有這段時(shí)間是阻塞的
4.3.復(fù)用型
理解場(chǎng)景:我雇了一只貓去守著釣魚(yú),而且這次拿了很多釣竿
讓貓?jiān)诤舆吺刂?,但是呢,我又怕貓偷吃,所以我也只能盯著貓不能去打麻將了,這階段我是阻塞的
當(dāng)有釣竿魚(yú)上鉤了,貓就叫我,然后我就過(guò)去把魚(yú)放在桶里,所以我從頭到尾一直都是阻塞的....
4.4.信號(hào)驅(qū)動(dòng)型
理解場(chǎng)景:我買(mǎi)了一個(gè)帶語(yǔ)音提示的魚(yú)竿
這次,我把魚(yú)竿搞好,我也依然去旁邊的麻將館打麻將了,
當(dāng)魚(yú)兒上鉤了,就語(yǔ)音提示我,主人,主人,魚(yú)上鉤了,然后我就去把魚(yú)兒放在桶里
只有把魚(yú)放在桶里,我需要去河邊,這段時(shí)間我是阻塞的
4.5.異步
理解場(chǎng)景:由于前幾次都是空軍,這次我就聘請(qǐng)了一個(gè)釣魚(yú)達(dá)人去釣
釣魚(yú)達(dá)人在釣魚(yú),我就去打麻將..
我麻將打完了,釣魚(yú)達(dá)人,就把魚(yú)兒給我了
5.五種I/O模型比較
阻塞型:一直都阻塞
非阻塞:只有魚(yú)兒放桶里是阻塞
復(fù)用型:也是一直阻塞
信號(hào)驅(qū)動(dòng):只有魚(yú)兒放桶里是阻塞
異步:完全不阻塞
6.模型實(shí)現(xiàn)的方式
Select: #Linux實(shí)現(xiàn) 對(duì)應(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), 對(duì)應(yīng)I/O復(fù)用模型 System V unix最早實(shí)現(xiàn)
Epoll: #Linux特有, 對(duì)應(yīng)I/O復(fù)用模型 具有信號(hào)驅(qū)動(dòng)I/O模型的某些特性
Kqueue: #FreeBSD實(shí)現(xiàn), 對(duì)應(yīng)I/O復(fù)用模型 具有信號(hào)驅(qū)動(dòng)I/O模型某些特性
/dev/poll:#SUN的Solaris實(shí)現(xiàn) 對(duì)應(yīng)I/O復(fù)用模型 具有信號(hào)驅(qū)動(dòng)I/O模型的某些特性
Iocp #Windows實(shí)現(xiàn), 對(duì)應(yīng)第5種(異步I/O)模型
7.select/poll/epoll
7.1.select
Select:POSIX所規(guī)定,目前幾乎在所有的平臺(tái)上支持,其良好跨平臺(tái)支持也是它的一個(gè)優(yōu)點(diǎn),本質(zhì)上是通過(guò)設(shè)置或
者檢查存放fd標(biāo)志位的數(shù)據(jù)結(jié)構(gòu)來(lái)進(jìn)行下一步處理
#缺點(diǎn)
1)單個(gè)進(jìn)程能夠監(jiān)視的文件描述符的數(shù)量存在最大限制,在Linux上一般為1024,可以通過(guò)修改宏定義FD_SETSIZE,
再重新編譯內(nèi)核實(shí)現(xiàn),但是這樣也會(huì)造成效率的降低
2)單個(gè)進(jìn)程可監(jiān)視的fd數(shù)量被限制,默認(rèn)是1024,修改此值需要重新編譯內(nèi)核
3)對(duì)socket是線(xiàn)性?huà)呙?,即采用輪?xún)的方法,效率較低
4)select 采取了內(nèi)存拷貝方法來(lái)實(shí)現(xiàn)內(nèi)核將 FD 消息通知給用戶(hù)空間,這樣一個(gè)用來(lái)存放大量fd的數(shù)據(jù)結(jié)構(gòu),
這樣會(huì)使得用戶(hù)空間和內(nèi)核空間在傳遞該結(jié)構(gòu)時(shí)復(fù)制開(kāi)銷(xiāo)大
7.2.poll
1)本質(zhì)上和select沒(méi)有區(qū)別,它將用戶(hù)傳入的數(shù)組拷貝到內(nèi)核空間,然后查詢(xún)每個(gè)fd對(duì)應(yīng)的設(shè)備狀態(tài)
2)其沒(méi)有最大連接數(shù)的限制,原因是它是基于鏈表來(lái)存儲(chǔ)的
3)大量的fd的數(shù)組被整體復(fù)制于用戶(hù)態(tài)和內(nèi)核地址空間之間,而不管這樣的復(fù)制是不是有意義
4)poll特點(diǎn)是"水平觸發(fā)",如果報(bào)告了fd后,沒(méi)有被處理,那么下次poll時(shí)會(huì)再次報(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),并且只會(huì)通知一次
使用"事件"的就緒通知方式,通過(guò)epoll_ctl注冊(cè)fd,一旦該fd就緒,內(nèi)核就會(huì)采用類(lèi)似callback的回調(diào)機(jī)制來(lái)激
活該fd,epoll_wait便可以收到通知
#優(yōu)點(diǎn):
1)沒(méi)有最大并發(fā)連接的限制:能打開(kāi)的FD的上限遠(yuǎn)大于1024(1G的內(nèi)存能監(jiān)聽(tīng)約10萬(wàn)個(gè)端口),具體查看
/proc/sys/fs/file-max,此值和系統(tǒng)內(nèi)存大小相關(guān)
2)效率提升:非輪詢(xún)的方式,不會(huì)隨著FD數(shù)目的增加而效率下降;只有活躍可用的FD才會(huì)調(diào)用callback函數(shù),
即epoll最大的優(yōu)點(diǎn)就在于它只管理"活躍"的連接,而跟連接總數(shù)無(wú)關(guān)
3)內(nèi)存拷貝,利用mmap(Memory Mapping)加速與內(nèi)核空間的消息傳遞;即epoll使用mmap減少?gòu)?fù)制開(kāi)銷(xiāo)
邊緣觸發(fā):只通知一次
8.什么是零拷貝
傳統(tǒng)Linux中 I/O 的問(wèn)題
傳統(tǒng)的Linux系統(tǒng)的標(biāo)準(zhǔn) I/O 接口(read、write)是基于數(shù)據(jù)拷貝的,也就是數(shù)據(jù)都是 copy_to_user 或者
copy_from_user,這樣做的好處是,通過(guò)中間緩存的機(jī)制,減少磁盤(pán) I/O 的操作,
但是壞處也很明顯,大量數(shù)據(jù)的拷貝,用戶(hù)態(tài)和內(nèi)核態(tài)的頻繁切換,會(huì)消耗大量的 CPU 資源,嚴(yán)重影響數(shù)據(jù)傳輸?shù)?br/>性能
統(tǒng)計(jì)表明,在Linux協(xié)議棧中,數(shù)據(jù)包在內(nèi)核態(tài)和用戶(hù)態(tài)之間的拷貝所用的時(shí)間甚至占到了數(shù)據(jù)包整個(gè)處理流
程時(shí)間的57.1%
零拷貝就是上述問(wèn)題的一個(gè)解決方案,盡量避免拷貝操作來(lái)緩解 CPU 的壓力。
零拷貝并沒(méi)有真正做到"0"拷貝,它更多是一種思想,很多的零拷貝技術(shù)都是基于這個(gè)思想去做的優(yōu)化
8.1.原始數(shù)據(jù)拷貝操作
8.2.MMAP:Memory Mapping
8.3.SENDFILE
8.4.DMA 輔助的 SENDFILE
9.Httpd MPM
HTTP中的三種請(qǐng)求處理模式(MPM)的區(qū)別
(1)prefork(預(yù)派生模式):多進(jìn)程I/o模型,每個(gè)進(jìn)程相應(yīng)一個(gè)請(qǐng)求 #-->>進(jìn)程模型,兩級(jí)結(jié)構(gòu)
主進(jìn)程--子進(jìn)程--線(xiàn)程--請(qǐng)求
|--子進(jìn)程--線(xiàn)程--請(qǐng)求
|--子進(jìn)程--線(xiàn)程--請(qǐng)求
優(yōu)點(diǎn):穩(wěn)定
缺點(diǎn):慢,占用資源(內(nèi)存),不適用于高并發(fā)場(chǎng)景
使用select 模型,最大并發(fā)1024
(2)worker:復(fù)用的多進(jìn)程I/O模型,多進(jìn)程多線(xiàn)程 #-->>線(xiàn)程模型,三級(jí)結(jié)構(gòu)
主進(jìn)程--子進(jìn)程--線(xiàn)程--請(qǐng)求
| --線(xiàn)程--請(qǐng)求
| --線(xiàn)程--請(qǐng)求
|--子進(jìn)程--線(xiàn)程--請(qǐng)求
| --線(xiàn)程--請(qǐng)求
| --線(xiàn)程--請(qǐng)求
優(yōu)點(diǎn):相比prefork,占用內(nèi)存較少,可以同時(shí)處理更多的請(qǐng)求
缺點(diǎn):使用keep-alive的長(zhǎng)連接方式,某個(gè)線(xiàn)程會(huì)一直被占據(jù),即使沒(méi)有傳輸數(shù)據(jù),也需要一直等待到超時(shí)才會(huì)被釋放。
(3)event 事件驅(qū)動(dòng)模型(epoll),增加了一個(gè)監(jiān)聽(tīng)線(xiàn)程 #-->>線(xiàn)程模型,三級(jí)結(jié)構(gòu)
監(jiān)聽(tīng)線(xiàn)程:用于向工作線(xiàn)程分配任務(wù)并和客戶(hù)端保持會(huì)話(huà)連接,超時(shí)之后監(jiān)聽(tīng)線(xiàn)程會(huì)刪除socket,工作線(xiàn)程只處理用戶(hù)請(qǐng)求,處理完之后將會(huì)話(huà)保持交于監(jiān)聽(tīng)線(xiàn)程,自己去處理新的請(qǐng)求,不再負(fù)責(zé)會(huì)話(huà)保持
主進(jìn)程--子進(jìn)程--監(jiān)聽(tīng)線(xiàn)程--請(qǐng)求1 空請(qǐng)求不被分配 請(qǐng)求3
| |--工作線(xiàn)程--請(qǐng)求1
| |--工作線(xiàn)程--請(qǐng)求3
| |--工作線(xiàn)程 處理完成請(qǐng)求,將keep-alived交給監(jiān)聽(tīng)線(xiàn)程,自己開(kāi)始等待處理新請(qǐng)求
與worker進(jìn)程很像,最大的區(qū)別在于,它解決了keep-alive場(chǎng)景下,長(zhǎng)期被占用的線(xiàn)程的資源浪費(fèi)問(wèn)題
優(yōu)點(diǎn):單線(xiàn)程響應(yīng)多請(qǐng)求,占據(jù)更少的內(nèi)存,高并發(fā)下表現(xiàn)更優(yōu)秀
缺點(diǎn):沒(méi)有線(xiàn)程安全控制
本文摘自 :https://blog.51cto.com/t