好湿?好紧?好多水好爽自慰,久久久噜久噜久久综合,成人做爰A片免费看黄冈,机机对机机30分钟无遮挡

主頁 > 知識庫 > 詳細介紹Linux IO

詳細介紹Linux IO

熱門標簽:地圖標注審核周期 蘭州電銷機器人加盟 電商外呼系統排名 電話機器人對家居行業幫助大嗎 合肥電銷外呼系統供應商 AI智能電銷機器人壞處 如何申請400的電話呀 沈陽ai電銷智能機器人 黑暗之魂3地圖標注

1.IO概述

分析一下寫操作:

char *buf = malloc(MAX_BUF_SIZE);

strncpy(buf, src, , MAX_BUF_SIZE);

fwrite(buf, MAX_BUF_SIZE, 1, fp);

fclose(fp);

以下圖為例:分析數據流寫入硬盤的過程

malloc的buf對于圖層中的application buffer,即應用程序的buffer;

調用fwrite后,把數據從application buffer 拷貝到了 CLib buffer,即C庫標準IObuffer。

fwrite返回后,數據還在CLib buffer,如果這時候進程core掉。這些數據會丟失。沒有寫到磁盤介質上。當調用fclose的時候,fclose調用會把這些數據刷新到磁盤介質上。

除了fclose方法外,還有一個主動刷新操作fflush函數,不過fflush函數只是把數據從CLib buffer 拷貝到page cache 中,并沒有刷新到磁盤上,從page cache刷新到磁盤上可以通過調用fsync函數完成。

fwrite是系統提供的最上層接口,也是最常用的接口。它在用戶進程空間開辟一個buffer,將多次小數據量相鄰寫操作先緩存起來,合并,最終調用write函數一次性寫入(或者將大塊數據分解多次write調用)。

Write函數通過調用系統調用接口,將數據從應用層copy到內核層,所以write會觸發內核態/用戶態切換。當數據到達page cache后,內核并不會立即把數據往下傳遞。而是返回用戶空間。數據什么時候寫入硬盤,有內核IO調度決定,所以write是一個異步調用。這一點和read不同,read調用是先檢查page cache里面是否有數據,如果有,就取出來返回用戶,如果沒有,就同步傳遞下去并等待有數據,再返回用戶,所以read是一個同步過程。當然你也可以把write的異步過程改成同步過程,就是在open文件的時候帶上O_SYNC標記。

數據到了page cache后,內核有pdflush線程在不停的檢測臟頁,判斷是否要寫回到磁盤中。把需要寫回的頁提交到IO隊列——即IO調度隊列。IO調度隊列調度策略調度何時寫回。

IO隊列有2個主要任務。一是合并相鄰扇區的,而是排序。合并相信很容易理解,排序就是盡量按照磁盤選擇方向和磁頭前進方向排序。因為磁頭尋道時間是和昂貴的。

這里IO隊列和我們常用的分析工具IOStat關系密切。IOStat中rrqm/s wrqm/s表示讀寫合并個數。avgqu-sz表示平均隊列長度。

內核中有多種IO調度算法。當硬盤是SSD時候,沒有什么磁道磁頭,人家是隨機讀寫的,加上這些調度算法反而畫蛇添足。OK,剛好有個調度算法叫noop調度算法,就是什么都不錯(合并是做了)。剛好可以用來配置SSD硬盤的系統。

從IO隊列出來后,就到了驅動層(當然內核中有更多的細分層,這里忽略掉),驅動層通過DMA,將數據寫入磁盤cache。

至于磁盤cache時候寫入磁盤介質,那是磁盤控制器自己的事情。如果想要睡個安慰覺,確認要寫到磁盤介質上。就調用fsync函數吧。可以確定寫到磁盤上了。

2.linux IO子系統和文件系統讀寫流程

I/O子系統是個層次很深的系統,數據請求從用戶空間最終到達磁盤,經過了復雜的數據流動。

read系統調用的處理分為用戶空間和內核空間處理兩部分。其中,用戶空間處理只是通過0x80中斷陷入內核,接著調用其中斷服務例程,即sys_read以進入內核處理流程。

對于read系統調用在內核的處理,如上圖所述,經過了VFS、具體文件系統,如ext2、頁高速緩沖存層、通用塊層、IO調度層、設備驅動層、和設備層。其中,VFS主要是用來屏蔽下層具體文件系統操作的差異,對上提供一個統一接口,正是因為有了這個層次,所以可以把設備抽象成文件。具體文件系統,則定義了自己的塊大小、操作集合等。引入cache層的目的,是為了提高IO效率。它緩存了磁盤上的部分數據,當請求到達時,如果在cache中存在該數據且是最新的,則直接將其傳遞給用戶程序,免除了對底層磁盤的操作。通用塊層的主要工作是,接收上層發出的磁盤請求,并最終發出IO請求(BIO)。IO調度層則試圖根據設置好的調度算法對通用塊層的bio請求合并和排序,回調驅動層提供的請求處理函數,以處理具體的IO請求。驅動層的驅動程序對應具體的物理設備,它從上層取出IO請求,并根據該IO請求中指定的信息,通過向具體塊設備的設備控制器發送命令的方式,來操縱設備傳輸數據。設備層都是具體的物理設備。

VFS層

內核函數sys_read是read系統調用在該層的入口點。它根據文件fd指定的索引,從當前進程描述符中取出相應的file對象,并調用vfs_read執行文件讀取操作。vfs_read會調用與具體文件相關的read函數執行讀取操作,file->f_op.read。然后,VFS將控制權交給了ext2文件系統。(ext2在此作為示例,進行解析)

Ext2文件系統層

通過ext2_file_operations結構知道,上述函數最終會調用到do_sync_read函數,它是系統通用的讀取函數。所以說,do_sync_read才是ext2層的真實入口。該層入口函數 do_sync_read 調用函數 generic_file_aio_read ,后者判斷本次讀請求的訪問方式,如果是直接 io (filp->f_flags 被設置了 O_DIRECT 標志,即不經過 cache)的方式,則調用 generic_file_direct_IO 函數;如果是 page cache 的方式,則調用 do_generic_file_read 函數。它會判斷該頁是否在頁高速緩存,如果是,直接將數據拷貝到用戶空間。如果不在,則調用page_cache_sync_readahead函數執行預讀(檢查是否可以預讀),它會調用mpage_readpages。如果仍然未能命中(可能不允許預讀或者其它原因),則直接跳轉readpage,執行mpage_readpage,從磁盤讀取數據。在mpage_readpages(一次讀多個頁)中,它會將連續的磁盤塊放入同一個BIO,并延緩BIO的提交,直到出現不連續的塊,則直接提交BIO,再繼續處理,以構造另外的BIO。

page cache 結構

圖5顯示了一個文件的 page cache 結構。文件被分割為一個個以 page 大小為單元的數據塊,這些數據塊(頁)被組織成一個多叉樹(稱為 radix 樹)。樹中所有葉子節點為一個個頁幀結構(struct page),表示了用于緩存該文件的每一個頁。在葉子層最左端的第一個頁保存著該文件的前4096個字節(如果頁的大小為4096字節),接下來的頁保存著文件第二個4096個字節,依次類推。樹中的所有中間節點為組織節點,指示某一地址上的數據所在的頁。此樹的層次可以從0層到6層,所支持的文件大小從0字節到16 T 個字節。樹的根節點指針可以從和文件相關的 address_space 對象(該對象保存在和文件關聯的 inode 對象中)中取得(更多關于 page cache 的結構內容請參見參考資料)。

mpage處理機制就是page cache層要處理的問題。

通用塊層

在緩存層處理末尾,執行mpage_submit_bio之后,會調用generic_make_request函數。這是通用塊層的入口函數。它將bio傳送到IO調度層進行處理。

IO調度層

對bio進行合并、排序,以提高IO效率。然后,調用設備驅動層的回調函數,request_fn,轉到設備驅動層處理。

設備驅動層

request函數對請求隊列中每個bio進行分別處理,根據bio中的信息向磁盤控制器發送命令。處理完成后,調用完成函數end_bio以通知上層完成。

3.IO之流程與buffer概覽

一般情況下,進程在io的時候,要依賴于內核中的一個buffer模塊來和外存發生數據交換行為。另一個角度來說,數據從應用進程自己的buffer流動到外存,中間要先拷貝到內核的buffer中,然后再由內核決定什么時候把這些載有數據的內核buffer寫出到外存。

“buffer cache”僅僅被內核用于常規文件(磁盤文件)的I/O操作。

內核中的buffer模塊-“buffer cache”(buffer,cache的功能兼備)

一般情況下,read,write系統調用并不直接訪問磁盤。這兩個系統調用僅僅是在用戶空間和內核空間的buffer之間傳遞目標數據。舉個例子,下面的write系統調用僅僅是把3個字節從用戶空間拷貝到內核空間的buffer之后就直接返回了

write(fd,”abc”,3);

在以后的某個時間點上,內核把裝著“abc”三個字節的buffer寫入(flush)磁盤。如果另外的進程在這個過程中想要讀剛才被打開寫的那個文件怎么辦?答案是:內核會從剛才的buffer提供要讀取的數據,而不是從磁盤讀。

當前系統上第一次讀一個文件時,read系統調用觸發內核以blocrk為單位從磁盤讀取文件數據,并把數據blocks存入內核buffer,然后read不斷地從這個buffer取需要的數據,直到buffer中的數據全部被讀完,接下來,內核從磁盤按順序把當前文件后面的blocks再讀入內核buffer,然后read重復之前的動作…

一般的文件訪問,都是這種不斷的順序讀取的行為,為了加速應用程序讀磁盤,unix的設計者們為這種普遍的順序讀取行為,設計了這樣的機制—-預讀,來保證進程在想讀后續數據的時候,這些后續數據已經的由內核預先從磁盤讀好并且放在buffer里了。這么做的原因是磁盤的io訪問比內存的io訪問要慢很多,指數級的差別。

read,write從語義和概念上來說,本來是必須要直接和磁盤交互的,調用時間非常長,應用每次在使用這兩個系統的時候,從表象上來說都是被卡住。而有了這些buffer,這些系統調用就直接和buffer交互就可以了,大幅的加速了應用執行。

Linux內核并沒有規定”buffer cache”的尺寸上線,原則上來說,除了系統正常運行所必需和用戶進程自身所必需的之外的內存都可以被”buffer cache”使用。而系統和用戶進程需要申請更多的內存的時候,”buffer cache”的內存釋放行為會被觸發,一些長久未被讀取,以及被寫過的臟頁就會被釋放和寫入磁盤,騰出內存,以便被需要的行為方使用。

”buffer cache”有五個flush的觸發點:

1.pdflush(內核線程)定期flush;

2.系統和其他進程需要內存的時候觸發它flush;

3.用戶手工sync,外部命令觸發它flush;

4.proc內核接口觸發flush,”echo 3 >/proc/sys/vm/drop_caches;

5.應用程序內部控制flush。

這個”buffer cache”從概念上的理解就是這些了,實際上,更準確的說,linux從2.4開始就不再維護獨立的”buffer cache”模塊了,而是把它的功能并入了”page cache”這個內存管理的子系統了,”buffer cache”現在已經是一個unix系統族的普遍的歷史概念了

高性能寫文件

寫100MB的數據

場景1,1次寫1個字節,總共write 100M次;

場景2,1次寫1K個字節,總共write 100K次;

場景3,1次寫4K個字節,總共write 25K次;

場景4,1次寫16k個字節,總共write大約不到7K次。

以上4種寫入方式,內核寫磁盤的次數基本相同,因為寫磁盤的單位是block,而不是字節。現在的系統默認的block都是4k。

第1種性能非常差,user time和system time執行時間都很長,既然寫盤次數都差不多,那他慢在哪兒呢?答案是系統調用的次數太多

第2種,user time和system time都顯著降低,不過system time降低幅度更大

第2種以后,性能差別就不是很高了,第3種和第4種性能幾乎一樣

有興趣的朋友可以試一試,如果你的服務器很好,可以適當放大測試樣本。

總而言之,得出的結論是以block的尺寸為write(fd, sizeof(buf),buf)的調用單位就可以了,再大對性能也沒什么太大的提高。

題外話:一個衡量涉及IO程序的好壞的粗略標準是“程序運行應該盡量集中在user time,避免大量的system time”以及“IO的時候肯定是需要一些應用層buf的,比如上述4個場景,匹配就可以了(比如場景3,場景1和場景2會導致系統調用次數太多,場景4使用的buf尺寸過于浪費)”

每個系統調用在返回的時候,會有一個從內核態向用戶態切換的間隙,每次在這個間隙里面,系統要干兩個事情—-遞送信號和進程調度,其中進程調度會重新計算全部RUN狀態進程的優先級。

系統調用太多的話,遞送信號和進程調度引起的計算量是不容忽視的。

精確地flush “buffer cache”

在很多業務場景下,我們僅僅調用write()把需要寫盤的數據推送至內核的”buffer cache”中,這是很不負責任的。或許我們應該不斷地頻繁地把”buffer cache”中的數據強制flush到磁盤,盡最大可能保證我們的業務數據盡量不因斷電而丟失。

天下沒有免費的午餐,既想要效率(寫入內核buffer),又想要安全性(數據必須flush到外存介質中才安全),這似乎是很矛盾的。SUSv3(Single UNIX Specification Version 3)給了這種需求一個折中的解決方案,讓OS盡量滿足我們的苛刻的要求。介紹這個折中方案之前,有兩個SUSv3提案的規范很重要,說明如下:

1.數據完整性同步(synchronized I/O data integrity)

一個常規文件所包含的信息有兩種:文件元數據和文件內容數據。

文件元數據包括:文件所屬用戶、組、訪問權限,文件尺寸,文件硬連接數目,最后訪問時間戳,最后修改時間戳,最后文件元數據修改時間戳,文件數據塊指針。

對于文件內容數據,大家應該都很清楚是什么東西。

對于寫操作,這個規范規定了,寫文件時保證文件內容數據和必要的文件元數據保持完整性即可。粗糙地舉個例子來解釋這個規范,某次flush內核中的數據到磁盤的時候,僅僅把文件內容數據寫入磁盤即可,但是如果這次寫文件導致了文件尺寸的變化,那么這個文件尺寸作為文件的元數據也需要被寫入磁盤,必要信息保持同步。而其他的文件元數據,例如修改時間,訪問時間一概略去,不需要同步。

2.文件完整性同步(synchronized I/O file integrity)

相對于數據完整性同步而言,這個規范規定了,所有內容數據以及元數據都要同步。

下面來介紹linux提供的幾種flush內核緩沖數據的幾種方案,相信看完之后,大家應該知道上述提及的折中方案是怎樣的:)

1.int fsync(int fd);

文件完整性同步;

2.int fdatasync(int fd);

數據完整性同步。

fdatasync相對于fsync的意義在于,fdatasync大致僅需要一次磁盤操作,而fsync需要兩次磁盤操作。舉例說明一下,假如文件內容改變了,但是文件尺寸并沒有發生變化,那調用fdatasync僅僅是把文件內容數據flush到磁盤,而fsync不僅僅把文件內容flush刷入磁盤,還要把文件的last modified time也同步到磁盤文件系統。last modified time屬于文件的元數據,一般情況下文件的元數據和文件內容數據在磁盤上不是連續存放的,寫完內容數據再寫元數據,必然涉及到磁盤的seek,而seek又是機械硬盤速度慢的根源。。。

在某些業務場景下,fdatasync和fsync的這點微小差別會導致應用程序性能的大幅差異。

3.sync_file_range()

這個接口是linux從2.6.17之后實現的,是linux獨有的非標準接口。這個接口提供了比fdatasync更為精準的flush數據的能力。詳細請參照man。

4.void sync(void);

強制”buffer cache”中的數據全部flush到磁盤,并且要遵循文件完整性同步。

上面4種方式介紹完畢,open()系統調用的打開文件的標志位,比如O_DSYNC諸如此類的標志,對flush數據的影響和上面幾個接口作用類似。

預讀

上面介紹了寫buffer以及如何控制buffer的flush,下面來講一講如何控制讀cache的行為。

讀cache這一塊,基本上,我們可以控制的就是文件的預讀。

我們從POSIX規定的一個接口來論述一下如何控制文件的預讀以及控制它的意義。接口原型如下:

int posix_fadvise(int fd, off_t offset, off_t len, int advice);

fd:打開文件的描述符其實;

offset和len:指明文件區域;

advice:預讀的方式。預讀方式及其意義如下:

POSIX_FADV_NORMAL:內核默認的預讀方式;

POSIX_FADV_RANDOM:內核禁用預讀。適合隨機讀文件的業務,每次按業務要求的量讀取數據,不多讀;

POSIX_FADV_SEQUENTIALP:內核把默認的預讀量(POSIX_FADV_NORMAL)擴大一倍;

POSIX_FADV_WILLNEED:讀取出來的內容會被應用程序多次訪問(就是應用程序會不斷的調用read()對這些內容不斷的讀);

POSIX_FADV_NOREUSE:讀取出來的內容只會被應用程序訪問一次,訪問一次之后就清理掉并且釋放內存。cache服務器,比如memcache或者redis啟動時,把文件內容加載到應用層cache,就是這個參數存在的典型場景;

POSIX_FADV_DONTNEED:應用程序后續不打算訪問指定范圍中的文件內容,內核從”page cache(buffer cache)”中刪除指定范圍的文件內容,釋放內存。

對于POSIX_FADV_WILLNEED這種方式,linux自己有一個特定接口,原型如下:

ssize_t readahead(int fd, off64_t offset, size_t count);

linux的”buffer cache”默認預讀128k。

實際上,OS全局控制”buffer cache”的操作接口不僅僅是上面提及的幾種,/proc/sys/vm/目錄下還有幾個參數可以從其他一些方面來控制”buffer cache”的行為,這部分內容在之后我整理筆記之后會介紹。

IO之標準C庫buffer

在論述這個主題之前,先介紹一下標準C庫和linux系統調用以及windows API之間的關系。

拿寫文件來舉個例子

linux下寫文件用write()

windows下寫文件用WriteFile()

這說明不同操作系統實現同樣的系統功能的接口應該是不一樣的。造成這種現狀是操作系統發展的歷史原因造成的,無法在操作系統的層面統一系統函數接口。同樣功能的程序在linux上寫一套,windows上又得寫另外一套,毫無移植性可言。如果要開發一個既能在linux跑,又能在windows上跑的程序,開發成本飆升!

為了解決這個移植性的問題,標準C庫利用了封裝技術,扮演了一個重要的角色,統一了部分基本功能接口。

標準C規定的寫文件的函數是fwrite(),就是不管在linux還是在windows上,各自都有一個標準C庫,庫函數封裝的下層細節不一樣,但是接口完全一樣,提供的功能完全一樣。

這是怎么做到的?猜一猜大致實現就知道了

在linux上,標準C接口fwrite()的實現偽代碼

size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream){ ... ... return write(stream->fd,buffer,count);}

在windows上,標準C接口fwrite()的實現偽代碼

size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream){#define OUT BOOL ret = false; OUT int optnum; ... ... ret = WriteFile(stream->filehandle, buffer, count, ;optnum,...); if( ret == true) return optnum; else return -1;}

內部實現不一致,沒關系,接口一樣就可以,不管在linux還是windows上,寫文件都用fwrite(),分別在各自平臺上編譯就可以了。

標準C就是這樣一個處于系統層面之上的應用層標準函數庫,為了統一各個操作系統上的函數接口而生。

回到我們的主題—-IO之應用層buffer

什么是應用層buffer?

回想一下我之前介紹的《IO之內核buffer”buffer cache”》,既然write()能把需要寫文件的數據推送到一個內核buffer來偷工減料欺騙應用層(為了加速I/O),說“我已經寫完文件并返回了”。那應用層的標準C庫的fwrite()按道理也可以為了加速,在真正調用write()之前,把數據放到(FILE*)stream->buffer中,等到多次調用fwrite(),直至(FILE*)stream->buffer中積攢的數據量達到(FILE*)stream->bufferlen這么多的時候,一次性的把這些數據全部送入write()接口,寫入內核,這是多么美妙啊。。。

實際上,標準C庫就是這么做的!

把fwrite()的linux實現再細致一下

過程其實仍然很粗糙,為了突出buffer的重點,計算stream->buffer是否滿,拷貝多少,填充多少這樣的細節和主題無關的東西我略去了

size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream){
…

if( stream->buffer滿 ){
write(stream->fd,stream->buffer,stream->bufferlen);

} else{
拷貝buffer內容至stream->buffer

}

…

return count;

//過程很粗糙,為了突出buffer的重點,計算stream->buffer是否滿,拷貝多少,填充多少這樣的細節和主題無關的東西我略去了

}

fwrite()在windows平臺的實現也基本上是這樣的,也有buffer。

值得一說的是,fread()也有一個讀cache來完成預讀。

setvbuf()和setbuf()都是控制這個標準C庫的buffer的。

還有fflush()是C庫用于flush數據的函數。

以上三個函數,如果大家有興趣,可以去看看linux上對應的man文檔。

重點是要知道不僅系統的內核有buffer,應用層的C庫同樣也有buffer。這些buffer的唯一作用就是為了加速應用,不讓應用老是卡在和磁盤交互上。

說個題外話,實際上對于磁盤、RAID卡、盤陣這樣的外存介質而言,他們各自在硬件上也都有一層前端的buffer,有時也叫cache,用來緩沖讀寫加速。cache越多,價格越貴,性能越好。大型存儲設備一般擁有多層cache,用的是昂貴的SSD。 
需要分享的一點經驗是,不管是標準C庫的buffer也好,內核的”buffer cache”也罷,我們終究對它們的控制力度是有限的。我們在做服務器程序的時候,如果業務上涉及太大的I/O量,需要做服務整體加速的時候,我們一般自己在業務層做一層自己的”buffer”,把業務數據buffer住,攢成以文件系統或者磁盤的block塊單位的大塊數據,然后集中寫,然后集中寫又有集中寫的策略。。。 
再引申一點內容,做高性能大流量的大站的架構,其中最重要幾個架構角色之一就是cache。前端CDN、后端memcache、redis、mysql內部cache等等,都是cache的應用場景,可以說”buffer cache”在服務器領域從軟件實現到硬件加速再到架構,真的是無處不在。

4.IO隊列和IO調度

IO調度和IO隊列

1.向塊設備寫入數據塊或是從塊設備讀出數據塊時,IO請求要先進入IO隊列,等待調度。

2.這個IO隊列和調度的目標是針對某個塊設備而言的,換句話說就是每個塊設備都有一個獨立的IO隊列。 

3.本篇所涉及的所謂的塊設備就是iostat命令里面列出的形如sda,sdb這樣的塊設備,并不是指物理磁盤。假如一個盤被分成5個分區,那么在這個主題下,5個分區代表5個塊設備,每個塊設備都有自己獨立的IO隊列。 

4.I/O 調度程序維護這些隊列,以便更有效地利用外存設備。簡單來說,IO調度程序將無序的IO操作變為大致有序的IO請求。比如調度的時候調整幾個IO請求的順序,合并那些寫盤區域相鄰的請求,或者按照寫磁盤的位置排序這些請求,以降低磁頭在磁盤上來回seek的操作,繼而加速IO。 

5.每個隊列的每一次調度都會把整個隊列過一遍,類似于進程調度的時候每次調度都要計算RUN隊列的全部進程的優先級。

 IO隊列深度

這個參數是iostat里面呈現的,字面意思顯而易見,就是IO隊列的深度,這個參數有何意義呢? 
針對每個機械物理盤,如果這個盤對應的IO隊列深度超過3,那么基本上表示這個盤處理IO硬件請求有點吃緊,這個盤對應的IO隊列深度怎么算呢? 
還拿上面一個盤被切成5個分區說事兒,5個分區對應5個塊設備,5個塊設備對應5個IO隊列,這5個IO隊列的深度總和就是這個機械物理盤的IO隊列深度了。 
如何解決這個盤的IO請求吃緊呢,最簡單的辦法硬件加速,把這個盤換成SSD盤:) 
說到這兒,我想提一提RAID卡。咱們使用RAID卡把幾個硬盤放在一起,讓系統只能看見一個塊設備。這個時候,假如有4個盤被放在RAID后面。那么這個RAID卡對應的塊設備的IO隊列深度允許超過12(4個磁盤,每個盤承受深度為3)。 
SSD盤可承受的IO隊列深度值很大,這個多少深度合適,我沒有注意具體觀察過。

 iostat另一個參數—-“%util”

實際生產系統上,我觀察IO設備是否吃緊,其實是看這個util的。這個值長期高于60,咱們就得考慮物理磁盤IO吃不消了。 
如果是使用機械硬盤的服務器上這個值達到90以上,最簡單的解決方案仍然是換SSD盤,換完之后這個值會下降到20左右,非常有效。

 IO調度算法

IO調度算法存在的意義有兩個:一是提高IO吞吐量,二是降低IO響應時間。然而IO吞吐量和IO響應時間往往是矛盾的,為了盡量平衡這兩者,IO調度器提供了多種調度算法來適應不同的IO請求場景。 
以下幾個算法介紹是網上抄來的,說的很詳細,作者水平很高:) 

1、NOOP 

該算法實現了最簡單的FIFO隊列,所有IO請求大致按照先來后到的順序進行操作。之所以說”大致”,原因是NOOP在FIFO的基礎上還做了相鄰IO請求的合并,并不是完完全全按照先進先出的規則滿足IO請求。 
假設有如下的io請求序列: 
100,500,101,10,56,1000 
NOOP將會按照如下順序滿足: 
100(101),500,10,56,1000

2、CFQ 

CFQ算法的全寫為Completely Fair Queuing。該算法的特點是按照IO請求的地址進行排序,而不是按照先來后到的順序來進行響應。 
假設有如下的io請求序列: 
100,500,101,10,56,1000 
CFQ將會按照如下順序滿足: 
100,101,500,1000,10,56 
在傳統的SAS盤上,磁盤尋道花去了絕大多數的IO響應時間。CFQ的出發點是對IO地址進行排序,以盡量少的磁盤旋轉次數來滿足盡可能多的IO請求。在CFQ算法下,SAS盤的吞吐量大大提高了。但是相比于NOOP的缺點是,先來的IO請求并不一定能被滿足,可能會出現餓死的情況。

3、DEADLINE 

DEADLINE在CFQ的基礎上,解決了IO請求餓死的極端情況。除了CFQ本身具有的IO排序隊列之外,DEADLINE額外分別為讀IO和寫IO提供了FIFO隊列。讀FIFO隊列的最大等待時間為500ms,寫FIFO隊列的最大等待時間為5s。FIFO隊列內的IO請求優先級要比CFQ隊列中的高,而讀FIFO隊列的優先級又比寫FIFO隊列的優先級高。優先級可以表示如下: 
FIFO(Read) > FIFO(Write) > CFQ 
這個算法特別適合數據庫這種隨機讀寫的場景。

4、ANTICIPATORY 

CFQ和DEADLINE考慮的焦點在于滿足離散IO請求上。對于連續的IO請求,比如順序讀,并沒有做優化。為了滿足隨機IO和順序IO混合的場景,Linux還支持ANTICIPATORY調度算法。ANTICIPATORY的在DEADLINE的基礎上,為每個讀IO都設置了6ms的等待時間窗口。如果在這6ms內OS收到了相鄰位置的讀IO請求,就可以立即滿足。

IO調度器算法的選擇,既取決于硬件特征,也取決于應用場景。 
在傳統的SAS盤上,CFQ、DEADLINE、ANTICIPATORY都是不錯的選擇;對于專屬的數據庫服務器,DEADLINE的吞吐量和響應時間都表現良好。然而在新興的固態硬盤比如SSD、Fusion IO上,最簡單的NOOP反而可能是最好的算法,因為其他三個算法的優化是基于縮短尋道時間的,而固態硬盤沒有所謂的尋道時間且IO響應時間非常短。

 IO調度算法的查看和設置

查看和修改IO調度器的算法非常簡單。假設我們要對sda進行操作,如下所示: 
cat /sys/block/sda/queue/scheduler 
echo ‘cfq' >/sys/block/sda/queue/scheduler 
還有持久化設置,不一一列舉了。

以上就是Linux IO介紹的詳細內容,更多關于Linux IO的資料請關注腳本之家其它相關文章!

您可能感興趣的文章:
  • Linux中的iostat命令使用教程
  • Linux IO多路復用之epoll網絡編程
  • Linux的Socket IO模型趣解
  • Linux 下的五種 IO 模型詳細介紹
  • 解析Linux高性能網絡IO和Reactor模型

標簽:隴南 黔南 河北 河池 黔南 通遼 淮南 常州

巨人網絡通訊聲明:本文標題《詳細介紹Linux IO》,本文關鍵詞  詳細,介紹,Linux,詳細,介紹,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《詳細介紹Linux IO》相關的同類信息!
  • 本頁收集關于詳細介紹Linux IO的相關信息資訊供網民參考!
  • 推薦文章
    主站蜘蛛池模板: 掀开奶罩边躁狠狠躁H工厂小说| 幽都监狱小说| 精品欧美一区二区精品久久| 337P粉嫩日本欧洲亚洲张悠雨| 欧美俄罗斯16一18xx| 日韩在线中文字幕| freevide0fvideo性欧美| 精品亚洲自慰AV无码喷奶水| 国产精品一线二线三线区别在哪里| 欧美日韩不卡一区| 好吊妞操| 男生舔女生胸| 久草网站在线| 国内国产精品天干天干| 吃小男生嫩嫩的玉茎| 欧美三级大尺度无删减版| 国产AV天堂亚洲AV麻豆| 亚洲国产第一区二区香蕉| 亚洲国产影院| 亚洲精品国产精品乱码不卡√香蕉 | 特级毛片WWW| 午夜性做爰A片免费看京东| 一级片短视频| 五月婷婷综合在线| 大陆老年人一级毛片免费看| 欲奴在线| 伊人影院久久| PANS国产大尺度私密视频| 二十四小时第二季在线播放| 日本韩国黄色| 夫妻性生活一级片| 妹妹的义务漫画| 久久久久麻豆V国产精| 福利视频 一区| 老**毛茸茸bbw视频| 亚洲AV乱码一区二区三区老胖妞 | 用力?哦?高潮?嘶喊| 停电了被男同桌狂揉我奶胸动态图| 国产网站免费| 免费黄网在线| 成年人视频在线观看免费|