前言
本文主要介紹Linux的五種網絡模型,僅涉及理論知識,不包含實踐嘗試。可作為快速了解指南
正文
IO模型就是Linux系統在進行作業系統讀寫任務時,對執行程序和資料緩沖區的不同管理模式
為什麼需要多種IO模型
作業系統為避免使用者程序對作業系統的核心程序造成記憶體幹擾,将計算機記憶體分為了核心空間和使用者空間
是以,使用者程序下所有涉及系統操作的指令(如本文涉及到的IO操作),都隻能通過調用Linux提供的API來進行。于是,使用者态時想要執行系統操作就分為兩個階段
- 使用者程序調用作業系統對應API
- 作業系統啟用核心程序完成操作
我們以IO為例,上述流程可粗略表示為如下圖示:
由于緩存區和阻塞的存在,IO的效率取決于兩個方面:
- 資料等待:核心等待資料就緒的時間如何利用(資料就緒的标志是其放入了核心區的buffer)
- 資料拷貝:核心與使用者之間拷貝資料的時間如何利用
上述疑問決定了我們需要不同的IO模型來實作對不同執行效率或讀寫限制的需求
阻塞IO與非阻塞IO(以讀取為例)
阻塞IO | 非阻塞IO |
---|---|
核心态處于等待資料與拷貝資料兩階段時,使用者态均阻塞 | 核心态處于等待資料階段時,使用者态空轉不斷輪循;核心态處于拷貝資料階段時,使用者态阻塞 |
阻塞IO的使用率最低 | 非阻塞IO并未帶來效率提升,反而增加了核心态處理壓力 |
IO多路複用
三種模式:select, poll, epoll
相同之處:第一階段都是由使用者态通過多方監聽指令向核心态發起讀資料的監聽請求,當不存在資料時阻塞;當至少有一方資料就緒,傳回可讀辨別;第二階段由使用者态根據可讀辨別發起讀請求,核心态拷貝資料至使用者态,使用者态阻塞至資料拷貝完成。過程如下圖所示,三種模式皆适用
PS: socket的fd是什麼[1]
[email protected]:~# ll /proc/1583/fd
total 0
lrwx------ 1 root root 64 Jul 19 12:37 7 -> socket:[18892]
lrwx------ 1 root root 64 Jul 19 12:37 8 -> socket:[18893]
這裡的7和8就是socket:[18892]和socket:[18893]對應的fd
select | poll | epoll |
---|---|---|
與select一緻 | ||
特色:采用1024bit的fd辨別socket就緒情況 | 特色:采用自定義的pollfd數組辨別socket就緒情況 | 特色:采用紅黑樹存儲監聽位置,采用list存儲就緒位置 |
執行方法:由使用者态在fd對應位置辨別監聽位置,調用select時将fd拷貝至核心态,核心周遊fd直到至少一個監聽位置就緒,置該位為1,其餘為0,傳回fd至使用者态 | 執行方法:與select一緻,僅傳遞參數變為pollfd數組 | 執行方法:使用者态調用epoll_create做初始化,在核心态記憶體建立紅黑樹和list;使用者态調用epoll_ctl向紅黑樹中建立監聽節點;使用者态調用epoll_wait等待監聽節點回調方法執行,核心态list拷貝至使用者态 |
缺點:需要重複拷貝;無法直接識别就緒的socket位置,需要周遊得知;最多監聽1024位 | 缺點:需要重複拷貝;無法直接識别就緒的socket位置,需要周遊得知;雖監聽無上限,但連結清單周遊速度慢 | 優勢:監聽資訊不需要重複拷貝,紅黑樹直接建立在核心态;可以直接通過list确定就緒的socket位置;監聽無上限,且紅黑樹的周遊複雜度不會随着節點增加而無限增加 |
epoll的服務端流程
用文字描述epoll服務端簡單實作流程(包括實作代碼)[2]
流程圖如下,可與上面的連結部落格對照了解
信号驅動IO與異步IO
信号驅動IO | 異步IO |
---|---|
缺點:采用隊列存儲信号,相比epoll的紅黑樹而言有上限,當并發量過大時,有溢出風險;由于并未區分監聽與就緒隊列,是以也存在與select和poll類似的頻繁拷貝問題 | 缺點:異步IO第二階段的非阻塞在高并發場景下會不停接收讀寫,導緻記憶體占用過高,進而緻使伺服器崩潰,必須主動限流,增加了實作的複雜程度。而epoll等同步IO由于二階段一個核心阻塞式執行讀寫任務,完成後才再次接收讀寫,一定程度上通過IO的高消耗緩解了高并發壓力,在一些場景下不需要主動限流,使用更為簡單 |