
?絡IO和磁盤IO詳解
1. 緩存IO
緩存I/O?被稱作標準I/O,?多數?件系統的默認I/O操作都是緩存I/O。在Linux的緩存I/O機制中,數據先從磁盤復制到內核空間的緩沖區,然后從內核空間緩沖區復制到應?程序的地址空間。
讀操作:操作系統檢查內核的緩沖區有沒有需要的數據,如果已經緩存了,那么就直接從緩存中返回;否則從磁盤中讀取,然后緩存在操作系統的緩存中。
寫操作:將數據從?戶空間復制到內核空間的緩存中。這時對?戶程序來說寫操作就已經完成,?于什么時候再寫到磁盤中由操作系統決定,除?顯?地調?了sync同步命令(詳情參考《》)。
緩存I/O的優點:1)在?定程度上分離了內核空間和?戶空間,保護系統本?的運?安全;2)可以減少讀盤的次數,從?提?性能。
緩存I/O的缺點:在緩存 I/O 機制中,DMA ?式可以將數據直接從磁盤讀到頁緩存中,或者將數據從頁緩存直接寫回到磁盤上,?不能直接在應?程序地址空間和磁盤之間進?數據傳輸,這樣,數據在傳輸過程中需要在應?程序地址空間(?戶空間)和緩存(內核空間)之間進?多次數據拷貝操作,這些數據拷貝操作所帶來的CPU以及內存開銷是?常?的。
2. 直接IO
直接IO就是應?程序直接訪問磁盤數據,?不經過內核緩沖區,這樣做的?的是減少?次從內核緩沖區到?戶程序緩存的數據復制。?如說數據庫管理系統這類應?,它們更傾向于選擇它們??的緩存機制,因為數據庫管理系統往往?操作系統更了解數據庫中存放的數據,數據庫管理系統可以提供?種更加有效的緩存機制來提?數據庫中數據的存取性能。
直接IO的缺點:如果訪問的數據不在應?程序緩存中,那么每次數據都會直接從磁盤加載,這種直接加載會?常緩存。通常直接IO與異步IO結合使?,會得到?較好的性能。(異步IO:當訪問數據的線程發出請求之后,線程會接著去處理其他事,?不是阻塞等待)
下圖分析了寫場景下的DirectIO和BufferIO:
?先,磁盤IO主要的延時是由(以15000rpm硬盤為例):機械轉動延時(機械磁盤的主要性能瓶頸,平均為2ms)+ 尋址延時(2~3ms)+ 塊傳輸延時(?般4k每塊,40m/s的傳輸速度,延時?般為0.1ms) 決定。(平均為5ms)
??絡IO主要延時由:服務器響應延時 + 帶寬限制 + ?絡延時 + 跳轉路由延時 + 本地接收延時決定。(?般為??到?千毫秒,受環境?擾極?)
所以兩者?般來說?絡IO延時要?于磁盤IO的延時。
?Redis作緩存是因為,Redis就是設計來做緩存的阿。
Reids作緩存的??優勢:
1, 簡單的K-V式數據存儲?式,單?的 get t 模式?傳統SQL性能提升顯著
2, 純in mem db 形式,將數據緩存在內存中,減少服務器磁盤IO時間。
更新?下數據源:
ref :
《?型?站技術架構:核?原理與案例分析》
作者:李晨曦
鏈接:www.zhihu/question/47589908/answer/114768530
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,?商業轉載請注明出處。
Google的Jeff Dean給的?些數據(?個talk的ppt, "Designs, Lessons and Advice from Building Large Distributed Systems" 23頁),可以看到1Gbps的?絡?硬盤的bandwidth?了很多,記住這些數據對設計?性能系統和對系統的性能估算很有幫助。
L1 cache reference 0.5 ns
Branch mispredict 5 ns
L2 cache reference 7 ns
Mutex lock/unlock 25 ns
Main memory reference 100 ns
Compress 1K bytes with Zippy 3,000 ns
Send 2K bytes over 1 Gbps network 20,000 ns
Read 1 MB quentially from memory 250,000 ns
Round trip within same datacenter 500,000 ns
Disk ek 10,000,000 ns
Read 1 MB quentially from disk 20,000,000 ns
Send packet CA->Netherlands->CA 150,000,000 ns
PIO與DMA
有必要簡單地說說慢速I/O設備和內存之間的數據傳輸?式。
PIO
我們拿磁盤來說,很早以前,磁盤和內存之間的數據傳輸是需要CPU控制的,也就是說如果我們讀取磁盤?件到內存中,數據要經過CPU存儲轉發,這種?式稱為PIO。顯然這種?式?常不合理,需要占??量的CPU時間來讀取?件,造成?件訪問時系統?乎停?響應。
DMA
后來,DMA(直接內存訪問,Direct Memory Access)取代了PIO,它可以不經過CPU?直接進?磁盤和內存的數據交換。在DMA模式下,CPU只需要向DMA控制器下達指令,讓DMA控制器來處理數據的傳送即
可,DMA控制器通過系統總線來傳輸數據,傳送完畢再通知CPU,這樣就在很?程度上降低了CPU占有率,??節省了系統資源,?它的傳輸速度與PIO的差異其實并不?分明顯,因為這主要取決于慢速設備的速度。
可以肯定的是,PIO模式的計算機我們現在已經很少見到了。
標準?件訪問?式
當應?程序調?read接?時,操作系統檢查在內核的?速緩存有沒有需要的數據,如果已經緩存了,那么就直接從緩存中返回,如果沒有,則從磁盤中讀取,然后緩存在操作系統的緩存中。
應?程序調?write接?時,將數據從?戶地址空間復制到內核地址空間的緩存中,這時對?戶程序來說,寫操作已經完成,?于什么時候再寫到磁盤中,由操作系統決定,除?顯?調?了sync同步命令。
內存映射(減少數據在?戶空間和內核空間之間的拷貝操作,適合?量數據傳輸)
Linux內核提供?種訪問磁盤?件的特殊?式,它可以將內存中某塊地址空間和我們要指定的磁盤?件相關聯,從?把我們對這塊內存的訪問轉換為對磁盤?件的訪問,這種技術稱為內存映射(Memory Mapping)。
操作系統將內存中的某?塊區域與磁盤中的?件關聯起來,當要訪問內存中的?段數據時,轉換為訪問?件的某?段數據。這種?式的?的同樣是減少數據從內核空間緩存到?戶空間緩存的數據復制操作,因為這兩個空間的數據是共享的。
內存映射是指將硬盤上?件的位置與進程邏輯地址空間中?塊??相同的區域??對應,當要訪問內存中?段數據時,轉換為訪問?件的某?段數據。這種?式的?的同樣是減少數據在?戶空間和內核空間之間的拷貝操作。當?量數據需要傳輸的時候,采?內存映射?式去訪問?件會獲得?較好的效率。
使?內存映射?件處理存儲于磁盤上的?件時,將不必再對?件執?I/O操作,這意味著在對?件進?處理時將不必再為?件申請并分配緩存,所有的?件緩存操作均由系統直接管理,由于取消了將?件數據加載到內存、數據從內存到?件的回寫以及釋放內存塊等步驟,使得內存映射?件在處理?數據量的?件時能起到相當重要的作?。
在?多數情況下,使?內存映射可以提?磁盤I/O的性能,它?須使?read()或write()等系統調?來訪問?件,?是通過mmap()系統調?來建?內存和磁盤?件的關聯,然后像訪問內存?樣?由地訪問?件。
有兩種類型的內存映射,共享型和私有型,前者可以將任何對內存的寫操作都同步到磁盤?件,?且所有映射同?個?件的進程都共享任意?個進程對映射內存的修改;后者映射的?件只能是只讀?件,所以不可以將對內存的寫同步到?件,?且多個進程不共享修改。顯然,共享型內存映射的效率偏低,因為如果?個?件被很多進程映射,那么每次的修改同步將花費?定的開銷。
直接I/O(繞過內核緩沖區,??管理I/O緩存區)
在Linux 2.6中,內存映射和直接訪問?件沒有本質上差異,因為數據從進程?戶態內存空間到磁盤都要經過兩次復制,即在磁盤與內核緩沖區之間以及在內核緩沖區與?戶態內存空間。
引?內核緩沖區的?的在于提?磁盤?件的訪問性能,因為當進程需要讀取磁盤?件時,如果?件內容已經在內核緩沖區中,那么就不需要再次訪問磁盤;?當進程需要向?件中寫?數據時,實際上只是寫到了內核緩沖區便告訴進程已經寫成功,?真正寫?磁盤是通過?定的策略進?延遲的。
然?,對于?些較復雜的應?,?如數據庫服務器,它們為了充分提?性能,希望繞過內核緩沖區,由?
?在?戶態空間實現并管理I/O緩沖區,包括緩存機制和寫延遲機制等,以?持獨特的查詢機制,?如數據庫可以根據更加合理的策略來提?查詢緩存命中率。另???,繞過內核緩沖區也可以減少系統內存的開銷,因為內核緩沖區本?就在使?系統內存。
應?程序直接訪問磁盤數據,不經過操作系統內核數據緩沖區,這樣做的?的是減少?次從內核緩沖區到?戶程序緩存的數據復制。這種?式通常是在對數據的緩存管理由應?程序實現的數據庫管理系統中。
直接I/O的缺點就是如果訪問的數據不在應?程序緩存中,那么每次數據都會直接從磁盤進?加載,這種直接加載會?常緩慢。通常直接I/O跟異步I/O結合使?會得到較好的性能。
Linux提供了對這種需求的?持,即在open()系統調?中增加參數選項O_DIRECT,?它打開的?件便可以繞過內核緩沖區的直接訪問,這樣便有效避免了CPU和內存的多余時間開銷。
順便提?下,與O_DIRECT類似的?個選項是O_SYNC,后者只對寫數據有效,它將寫?內核緩沖區的數據?即寫?磁盤,將機器故障時數據的丟失減少到最?,但是它仍然要經過內核緩沖區。
ndfile/零拷貝(?絡I/O,kafka?到此特性)
1)操作系統將數據從磁盤復制到操作系統內核的頁緩存中
2)應?將數據從內核緩存復制到應?的緩存中
3)應?將數據寫回內核的Socket緩存中
4)操作系統將數據從Socket緩存區復制到?卡緩存,然后將其通過?絡發出
1、當調?read系統調?時,通過DMA(Direct Memory Access)將數據copy到內核模式
2、然后由CPU控制將內核模式數據copy到?戶模式下的 buffer中
3、read調?完成后,write調??先將?戶模式下 buffer中的數據copy到內核模式下的socket buffer中
4、最后通過DMA copy將內核模式下的socket buffer中的數據copy到?卡設備中傳送。
從上?的過程可以看出,數據??從內核模式到?戶模式?了?圈,浪費了兩次copy,?這兩次copy都是CPU copy,即占?CPU資源。
通過ndfile傳送?件只需要?次系統調?,當調? ndfile時:
1、?先通過DMA copy將數據從磁盤讀取到kernel buffer中
2、然后通過CPU copy將數據從kernel buffer copy到sokcet buffer中
3、最終通過DMA copy將socket buffer中數據copy到?卡buffer中發送
ndfile與read/write?式相?,少了?次模式切換?次CPU copy。但是從上述過程中也可以發現從kernel buffer中將數據copy到socket buffer是沒必要的。
為此,Linux2.4內核對ndfile做了改進,下圖所?
改進后的處理過程如下:
1、DMA copy將磁盤數據copy到kernel buffer中
2、向socket buffer中追加當前要發送的數據在kernel buffer中的位置和偏移量
3、DMA gather copy根據socket buffer中的位置和偏移量直接將kernel buffer中的數據copy到?卡上。
經過上述過程,數據只經過了2次copy就從磁盤傳送出去了。(事實上這個Zero copy是針對內核來講的,數據在內核模式下是Zero-copy的)。
當前許多?性能http rver都引?了ndfile機制,如nginx,lighttpd等。
Java NIO中ansferTo(long position, long count, WriteableByteChannel target)?法將當前通道中的數據傳送到?標通道target中,在?持Zero-Copy的linux系統中,transferTo()的實現依賴于 ndfile()調?。
傳統?式對?零拷貝?式:
整個數據通路涉及4次數據復制和2個系統調?,如果使?ndfile則可以避免多次數據復制,操作系統可以直接將數據從內核頁緩存中復制到?卡緩存,這樣可以??加快整個過程的速度。
?多數時候,我們都在向Web服務器請求靜態?件,?如圖?、樣式表等,根據前?的介紹,我們知道在處理這些請求的過程中,磁盤?件的數據先要經過內核緩沖區,然后到達?戶內存空間,因為是不需要任何處理的靜態數據,所以它們?被送到?卡對應的內核緩沖區,接著再被送??卡進?發送。
數據從內核出去,繞了?圈,?回到內核,沒有任何變化,看起來真是浪費時間。在Linux 2.4的內核中,嘗試性地引?了?個稱為khttpd的內核級Web服務器程序,它只處理靜態?件的請求。引?它的?的便在于內核希望請求的處理盡量在內核完成,減少內核態的切換以及?戶態數據復制的開銷。
同時,Linux通過系統調?將這種機制提供給了開發者,那就是ndfile()系統調?。它可以將磁盤?件的特定部分直接傳送到代表客戶端的socket描述符,加快了靜態?件的請求速度,同時也減少了CPU和內存的開銷。
在OpenBSD和NetBSD中沒有提供對ndfile的?持。通過strace的跟蹤看到了Apache在處理151字節
的??件時,使?了mmap()系統調?來實現內存映射,但是在Apache 處理較??件的時候,內存映射會導致較?的內存開銷,得不償失,所以Apache使?了ndfile64()來傳送?件,ndfile64()是ndfile()的擴展實現,它在Linux 2.4之后的版本中提供。
這并不意味著ndfile在任何場景下都能發揮顯著的作?。對于請求較?的靜態?件,ndfile發揮的作?便顯得不那么重要,通過壓?測試,我們模擬100個并發?戶請求151字節的靜態?件,是否使?ndfile的吞吐率?乎是相同的,可見在處理??件請求時,發送數據的環節在整個過程中所占時間的?例相?于??件請求時要?很多,所以對于這部分的優化效果?然不?分明顯。