一、用戶空間和內核空間
應用需要通過Linux內核與硬件交互。
內核本質也是應用,運行的時候也需要CPU資源、內存資源。用戶應用也在消耗這些資源。
為了避免用戶應用導致沖突甚至內核崩潰,用戶應用與內核是分離的:
尋址空間:無論內核還是用戶應用,都無法直接訪問物理內存,而是分配虛擬的內存空間,映射到不同的物理內存空間。內核和用戶應用,再去訪問虛擬內存空間,就需要有對應的虛擬地址(無符號的整數)
示例:32位系統,帶寬32,地址的最大值就是2的32次方32位程序最大尋址空間,也就是尋址的范圍從0到2的32次方,也就是4GB.
IO在用戶空間和內核空間切換的整體流程:
二、阻塞IO
訪問流程圖
顧名思義,阻塞IO就是兩個階段都必須阻塞等待。
三、非阻塞IO
顧名思義,非阻塞IO的操作會立即返回結果而不是阻塞用戶進程。
可以看到,非阻塞IO模型中,用戶進程在第一個階段是非阻塞,第二個階段是阻塞狀態。雖然是非阻塞,但是性能并沒有得到提高。而且忙等機制導致CPU空轉,CPU使用率暴增。
四、IO多路復用 1、背景
無論是阻塞IO還是非阻塞IO,用戶應用在一階段都需要調用來獲取數據,差別在于無數據時的處理方案:
比如服務端處理客戶端請求時,在單線程情況下,只能依次處理每一個,如果正在處理的soket恰好未就緒(數據不可讀或不可寫),線程就會被阻寒,所有其它客戶端都必須等待,性能自然會很差。
這就像服務員給顧客點餐,分兩步:
1、顧客思考要吃什么(等待數據就緒);
2、顧客想好了,開始點餐(讀取數據)。
第一步要提高效率的幾種方法:
1、方案一:增加更多服務員(多線程)
2、方案二:不排隊,誰想好了吃什么(數據就緒了),服務員就給誰點餐(用戶應用就去讀取數據)
那么問題來了:用戶進程如何知道內核中數據是否就緒呢?
2、IO多路復用
文件描述符(File ):簡稱FD,是一個從0 開始遞增的無符號整數,用來關聯Linux中的一個文件。在Linux中,一切皆文件,例如常規文件、視頻、硬件設備等,當然也包括網絡套接字 ()。
IO多路復用:是利用單個線程來同時監聽多個FD,并在某個FD可讀、可寫時得到通知,從而避免無效的等待,充分利用CPU資源。
監聽FD的方式、通知的方式又有多種實現,常見的有:
1、
2、poll
3、epoll
差異:
(1)和poll只會通知用戶進程有FD就緒,但不確定具體是哪個FD,需要用戶進程逐個遍歷FD來確認;
(2)epoll則會在通知用戶進程FD就緒的同時,把已就緒的FD寫入用戶空間
3、 (1)底層框架
是Linux中最早的I/O多路復用時限方案:
(2)執行流程 用戶空間創建 rfds,默認值0,大小位用戶空間假如要監聽 fd=1,2,5,把1、2、5bit位置為1用戶空間執行(5+1, rfds, null, null, 3)用戶空間拷貝 到內核空間內核空間遍歷內核空間沒有就緒,則休眠。內核空間等待數據就緒,被喚醒或超時。未就緒的改成0內核空間拷貝 到用戶空間,覆蓋用戶空間的用戶空間遍歷,找到就緒的fd,讀取其中數據
(3) 模式存在的問題 4、poll (1)底層框架
poll模式對模式進行了簡單改進,但性能提升不明顯。
(2)執行流程 (3)對比 5、epoll (1)底層代碼
epoll模式是對和poll的改進32位程序最大尋址空間,它提供了三個函數:
(2)執行流程
1、調用(1),創建epoll實例
2、調用(…),添加要監聽的FD,關聯,當觸發時,把對應的FD加入到鏈表中。
3、(…, )等待FD就緒
6、總結
1、模式存在的三個問題:
7、事件通知機制
當FD有數據可讀時,我們調用就可以得到通知。事件通知的模式有兩種:
區別:
拷貝數據之前,會將鏈表中的fd從中斷開連接,然后拷貝。
假如數據沒有處理完,
當采用ET時,直接刪掉fd,再次調用,中沒有數據;
當采用LT,會再次添加到 ,再次調用,中有數據;
結論:
8、web服務流程
基于epoll模式的web服務的基本流程圖:
五、信號驅動IO
信號驅動IO是與內核建立SIGIO的信號關聯并設置回調,當內核有FD就緒時,會發出SIGIO信號通知用戶,期間用戶應用可
以執行其它業務,無需阻塞等待,
當有大量IO操作時,信號較多,SIGIO處理函數不能及時處理可能導致信號隊列溢出。
而且內核空間與用戶空間的頻繁信號交互性能也較低。
六、異步IO
IO操作是同步還是異步,關鍵看數據在內核空間與用戶空間的拷貝過程(數據讀寫的IO操作),也就是階段二是同步還是異步:
七、Redis網絡模型 面試題:Redis到底是單線程還是多線程? 在Redis版本迭代過程中,在兩個重要的時間點上引入了多線程支持: Redis為什么要選擇單線程? 1、單線程
Redis通過IO多路復用來提高網絡性能,并且支持各種不同的多路復用實現,并且將這些實現進行封裝,提供了統一的高性能事件庫API庫AE:
ae.c文件判斷服務器類型,選擇執行哪個ae.c文件
Redis單線程網絡模型的整個流程:
整個流程:
Redi6.0版本中引入了多線程,目的是為了提高IO讀寫效率。因此在解析客戶端命令、寫響應結果時采用了多線程。核心的命令執行、IO多路復用模塊依然是由主線程執行。