深入理解?Linux的?I/O?系統(tǒng)
[導讀]↓推薦關注↓傳統(tǒng)的SystemCallI/O在Linux系統(tǒng)中,傳統(tǒng)的訪問方式是通過write()和read()兩個系統(tǒng)調用實現(xiàn)的,通過read()函數(shù)讀取文件到到緩存區(qū)中,然后通過write()方法把緩存中的數(shù)據輸出到網絡端口。read(file_fd,?tmp_buf,?le...
傳統(tǒng)的 System Call I/O
在 Linux 系統(tǒng)中,傳統(tǒng)的訪問方式是通過 write() 和 read() 兩個系統(tǒng)調用實現(xiàn)的,通過 read() 函數(shù)讀取文件到到緩存區(qū)中,然后通過 write() 方法把緩存中的數(shù)據輸出到網絡端口。
write(socket_fd, tmp_buf, len); 下圖分別對應傳統(tǒng) I/O 操作的數(shù)據讀寫流程,整個過程涉及 2 次 CPU 拷貝、2 次 DMA 拷貝,總共 4 次拷貝,以及 4 次上下文切換。
-
CPU 拷貝:
由 CPU 直接處理數(shù)據的傳送,數(shù)據拷貝時會一直占用 CPU 的資源。
-
DMA 拷貝:
由 CPU 向DMA磁盤控制器下達指令,讓 DMA 控制器來處理數(shù)據的傳送,數(shù)據傳送完畢再把信息反饋給 CPU,從而減輕了 CPU 資源的占有率。
-
上下文切換:
當用戶程序向內核發(fā)起系統(tǒng)調用時,CPU 將用戶進程從用戶態(tài)切換到內核態(tài);
當系統(tǒng)調用返回時,CPU 將用戶進程從內核態(tài)切換回用戶態(tài)。
讀操作
當應用程序執(zhí)行 read 系統(tǒng)調用讀取一塊數(shù)據的時候,如果這塊數(shù)據已經存在于用戶進程的頁內存中,就直接從內存中讀取數(shù)據。
基于傳統(tǒng)的 I/O 讀取方式,read 系統(tǒng)調用會觸發(fā) 2 次上下文切換,1 次 DMA 拷貝和 1 次 CPU 拷貝。
- 用戶進程通過 read() 函數(shù)向 Kernel 發(fā)起 System Call,上下文從 user space 切換為 kernel space。
- CPU 利用 DMA 控制器將數(shù)據從主存或硬盤拷貝到 kernel space 的讀緩沖區(qū)(Read Buffer)。
- CPU 將讀緩沖區(qū)(Read Buffer)中的數(shù)據拷貝到 user space 的用戶緩沖區(qū)(User Buffer)。
- 上下文從 kernel space 切換回用戶態(tài)(User Space),read 調用執(zhí)行返回。
寫操作
當應用程序準備好數(shù)據,執(zhí)行 write 系統(tǒng)調用發(fā)送網絡數(shù)據時,先將數(shù)據從用戶空間的頁緩存拷貝到內核空間的網絡緩沖區(qū)(Socket Buffer)中,然后再將寫緩存中的數(shù)據拷貝到網卡設備完成數(shù)據發(fā)送。
基于傳統(tǒng)的 I/O 寫入方式,write() 系統(tǒng)調用會觸發(fā) 2 次上下文切換,1 次 CPU 拷貝和 1 次 DMA 拷貝。
- 用戶進程通過 write() 函數(shù)向 kernel 發(fā)起 System Call,上下文從 user space 切換為 kernel space。
- CPU 將用戶緩沖區(qū)(User Buffer)中的數(shù)據拷貝到 kernel space 的網絡緩沖區(qū)(Socket Buffer)。
- CPU 利用 DMA 控制器將數(shù)據從網絡緩沖區(qū)(Socket Buffer)拷貝到 NIC 進行數(shù)據傳輸。
- 上下文從 kernel space 切換回 user space,write 系統(tǒng)調用執(zhí)行返回。
網絡 I/O
磁盤 I/O
高性能優(yōu)化的 I/O
- 零拷貝技術。
- 多路復用技術。
- 頁緩存(PageCache)技術。
- 如果在,則放棄訪問磁盤,而直接從頁緩存中讀取。
- 如果不在,則內核調度塊 I/O 操作從磁盤去讀取數(shù)據,并讀入緊隨其后的少數(shù)幾個頁面(不少于一個頁面,通常是三個頁面),然后將數(shù)據放入頁緩存中。
-
空閑內存低于一個特定閾值。
-
臟頁在內存中駐留超過一個特定的閾值時。
-
當用戶進程調用 sync() 和 fsync() 系統(tǒng)調用時。
存儲設備的 I/O 棧
由圖可見,從系統(tǒng)調用的接口再往下,Linux 下的 IO 棧致大致有三個層次:
-
文件系統(tǒng)層,以 write 為例,內核拷貝了 write 參數(shù)指定的用戶態(tài)數(shù)據到文件系統(tǒng) Cache 中,并適時向下層同步。
-
塊層,管理塊設備的 IO 隊列,對 IO 請求進行合并、排序(還記得操作系統(tǒng)課程學習過的 IO 調度算法嗎?)。
-
設備層,通過 DMA 與內存直接交互,完成數(shù)據和具體設備之間的交互。
I/O Buffering
如圖,當程序調用各類文件操作函數(shù)后,用戶數(shù)據(User Data)到達磁盤(Disk)的流程如圖所示。
作者:范桂颶 整理:極客重生- EOF -https://is-cloud.blog.csdn.net/article/details/105897963





