溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Linux讀寫機(jī)制及如何優(yōu)化

發(fā)布時間:2022-02-19 10:23:36 來源:億速云 閱讀:161 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹了Linux讀寫機(jī)制及如何優(yōu)化的相關(guān)知識,內(nèi)容詳細(xì)易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇Linux讀寫機(jī)制及如何優(yōu)化文章都會有所收獲,下面我們一起來看看吧。

Linux讀寫機(jī)制及如何優(yōu)化

緩存

緩存是用來減少高速設(shè)備訪問低速設(shè)備所需平均時間的組件,文件讀寫涉及到計算機(jī)內(nèi)存和磁盤,內(nèi)存操作速度遠(yuǎn)遠(yuǎn)大于磁盤,如果每次調(diào)用read,write都去直接操作磁盤,一方面速度會被限制,一方面也會降低磁盤使用壽命,因此不管是對磁盤的讀操作還是寫操作,操作系統(tǒng)都會將數(shù)據(jù)緩存起來。

Page Cache

頁緩存(Page Cache)是位于內(nèi)存和文件之間的緩沖區(qū),它實際上也是一塊內(nèi)存區(qū)域,所有的文件IO(包括網(wǎng)絡(luò)文件)都是直接和頁緩存交互,操作系統(tǒng)通過一系列的數(shù)據(jù)結(jié)構(gòu),比如inode, address_space, struct page,實現(xiàn)將一個文件映射到頁的級別,這些具體數(shù)據(jù)結(jié)構(gòu)及之間的關(guān)系我們暫且不討論,只需知道頁緩存的存在以及它在文件IO中扮演著重要角色,很大一部分程度上,文件讀寫的優(yōu)化就是對頁緩存使用的優(yōu)化

Dirty Page

頁緩存對應(yīng)文件中的一塊區(qū)域,如果頁緩存和對應(yīng)的文件區(qū)域內(nèi)容不一致,則該頁緩存叫做臟頁(Dirty Page)。對頁緩存進(jìn)行修改或者新建頁緩存,只要沒有刷磁盤,都會產(chǎn)生臟頁

查看頁緩存大小

linux上有兩種方式查看頁緩存大小,一種是free命令

$ free
            total       used       free     shared    buffers     cached
Mem:      20470840    1973416   18497424        164     270208    1202864
-/+ buffers/cache:     500344   19970496
Swap:            0          0          0

cached那一列就是頁緩存大小,單位Byte

另一種是直接查看/proc/meminfo,這里我們只關(guān)注兩個字段

Cached:          1202872 kB
Dirty:                52 kB

Cached是頁緩存大小,Dirty是臟頁大小

臟頁回寫參數(shù)

Linux有一些參數(shù)可以改變操作系統(tǒng)對臟頁的回寫行為

$ sysctl -a 2>/dev/null | grep dirty
vm.dirty_background_ratio = 10
vm.dirty_background_bytes = 0
vm.dirty_ratio = 20
vm.dirty_bytes = 0
vm.dirty_writeback_centisecs = 500
vm.dirty_expire_centisecs = 3000

vm.dirty_background_ratio是內(nèi)存可以填充臟頁的百分比,當(dāng)臟頁總大小達(dá)到這個比例后,系統(tǒng)后臺進(jìn)程就會開始將臟頁刷磁盤(vm.dirty_background_bytes類似,只不過是通過字節(jié)數(shù)來設(shè)置);vm.dirty_ratio是絕對的臟數(shù)據(jù)限制,內(nèi)存里的臟數(shù)據(jù)百分比不能超過這個值。如果臟數(shù)據(jù)超過這個數(shù)量,新的IO請求將會被阻擋,直到臟數(shù)據(jù)被寫進(jìn)磁盤;vm.dirty_writeback_centisecs指定多長時間做一次臟數(shù)據(jù)寫回操作,單位為百分之一秒;vm.dirty_expire_centisecs指定臟數(shù)據(jù)能存活的時間,單位為百分之一秒,比如這里設(shè)置為30秒,在操作系統(tǒng)進(jìn)行寫回操作時,如果臟數(shù)據(jù)在內(nèi)存中超過30秒時,就會被寫回磁盤.

這些參數(shù)可以通過 sudo sysctl -w vm.dirty_background_ratio=5 這樣的命令來修改,需要root權(quán)限,也可以在root用戶下執(zhí)行 echo 5 > /proc/sys/vm/dirty_background_ratio 來修改

文件讀寫流程

在有了頁緩存和臟頁的概念后,我們再來看文件的讀寫流程

讀文件
1.用戶發(fā)起read操作
2.操作系統(tǒng)查找頁緩存
 a.若未命中,則產(chǎn)生缺頁異常,然后創(chuàng)建頁緩存,并從磁盤讀取相應(yīng)頁填充頁緩存
 b.若命中,則直接從頁緩存返回要讀取的內(nèi)容
3.用戶read調(diào)用完成
寫文件
1.用戶發(fā)起write操作
2.操作系統(tǒng)查找頁緩存
 a.若未命中,則產(chǎn)生缺頁異常,然后創(chuàng)建頁緩存,將用戶傳入的內(nèi)容寫入頁緩存
 b.若命中,則直接將用戶傳入的內(nèi)容寫入頁緩存
3.用戶write調(diào)用完成
4.頁被修改后成為臟頁,操作系統(tǒng)有兩種機(jī)制將臟頁寫回磁盤
5.用戶手動調(diào)用fsync()
6.由pdflush進(jìn)程定時將臟頁寫回磁盤

頁緩存和磁盤文件是有對應(yīng)關(guān)系的,這種關(guān)系由操作系統(tǒng)維護(hù),對頁緩存的讀寫操作是在內(nèi)核態(tài)完成,對用戶來說是透明的

文件讀寫的優(yōu)化思路

不同的優(yōu)化方案適應(yīng)于不同的使用場景,比如文件大小,讀寫頻次等,這里我們不考慮修改系統(tǒng)參數(shù)的方案,修改系統(tǒng)參數(shù)總是有得有失,需要選擇一個平衡點(diǎn),這和業(yè)務(wù)相關(guān)度太高,比如是否要求數(shù)據(jù)的強(qiáng)一致性,是否容忍數(shù)據(jù)丟失等等。優(yōu)化的思路有以下兩點(diǎn):

1.最大化利用頁緩存

2.減少系統(tǒng)api調(diào)用次數(shù)

第一點(diǎn)很容易理解,盡量讓每次IO操作都命中頁緩存,這比操作磁盤會快很多,第二點(diǎn)提到的系統(tǒng)api主要是read和write,由于系統(tǒng)調(diào)用會從用戶態(tài)進(jìn)入內(nèi)核態(tài),并且有些還伴隨這內(nèi)存數(shù)據(jù)的拷貝,因此在有些場景下減少系統(tǒng)調(diào)用也會提高性能

readahead

readahead是一種非阻塞的系統(tǒng)調(diào)用,它會觸發(fā)操作系統(tǒng)將文件內(nèi)容預(yù)讀到頁緩存中,并且立馬返回,函數(shù)原型如下

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

在通常情況下,調(diào)用readahead后立馬調(diào)用read并不會提高讀取速度,我們通常在批量讀取或在讀取之前一段時間調(diào)用readahead,假設(shè)如下場景,我們需要連續(xù)讀取1000個1M的文件,有如下兩個方案,偽代碼如下

直接調(diào)用read函數(shù)
char* buf = (char*)malloc(10*1024*1024);for (int i = 0; i read(fd, buf, size);
   // do something with buf
   close(fd);
}
先批量調(diào)用readahead再調(diào)用read
int* fds = (int*)malloc(sizeof(int)*1000);
int* fd_size = (int*)malloc(sizeof(int)*1000);for (int i = 0; i for (int i = 0; i read(fds[i], buf, fd_size[i]);
   // do something with buf
   close(fds[i]);
}

感興趣的可以寫代碼實際測試一下,需要注意的是在測試前必須先回寫臟頁和清空頁緩存,執(zhí)行如下命令

sync && sudo sysctl -w vm.drop_caches=3

可通過查看/proc/meminfo中的Cached及Dirty項確認(rèn)是否生效

通過測試發(fā)現(xiàn),第二種方法比第一種讀取速度大約提高10%-20%,這種場景下是批量執(zhí)行readahead后立馬執(zhí)行read,優(yōu)化空間有限,如果有一種場景可以在read之前一段時間調(diào)用readahead,那將大大提高read本身的讀取速度

這種方案實際上是利用了操作系統(tǒng)的頁緩存,即提前觸發(fā)操作系統(tǒng)將文件讀取到頁緩存,并且操作系統(tǒng)對缺頁處理、緩存命中、緩存淘汰都由一套完善的機(jī)制,雖然用戶也可以針對自己的數(shù)據(jù)做緩存管理,但和直接使用頁緩存比并沒有多大差別,而且會增加維護(hù)代價

mmap

mmap是一種內(nèi)存映射文件的方法,即將一個文件或者其它對象映射到進(jìn)程的地址空間,實現(xiàn)文件磁盤地址和進(jìn)程虛擬地址空間中一段虛擬地址的一一對映關(guān)系,函數(shù)原型如下

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

實現(xiàn)這樣的映射關(guān)系后,進(jìn)程就可以采用指針的方式讀寫操作這一段內(nèi)存,而系統(tǒng)會自動回寫臟頁面到對應(yīng)的文件磁盤上,即完成了對文件的操作而不必再調(diào)用read,write等系統(tǒng)調(diào)用函數(shù)。如下圖所示

Linux讀寫機(jī)制及如何優(yōu)化

mmap除了可以減少read,write等系統(tǒng)調(diào)用以外,還可以減少內(nèi)存的拷貝次數(shù),比如在read調(diào)用時,一個完整的流程是操作系統(tǒng)讀磁盤文件到頁緩存,再從頁緩存將數(shù)據(jù)拷貝到read傳遞的buffer里,而如果使用mmap之后,操作系統(tǒng)只需要將磁盤讀到頁緩存,然后用戶就可以直接通過指針的方式操作mmap映射的內(nèi)存,減少了從內(nèi)核態(tài)到用戶態(tài)的數(shù)據(jù)拷貝

mmap適合于對同一塊區(qū)域頻繁讀寫的情況,比如一個64M的文件存儲了一些索引信息,我們需要頻繁修改并持久化到磁盤,這樣可以將文件通過mmap映射到用戶虛擬內(nèi)存,然后通過指針的方式修改內(nèi)存區(qū)域,由操作系統(tǒng)自動將修改的部分刷回磁盤,也可以自己調(diào)用msync手動刷磁盤

關(guān)于“Linux讀寫機(jī)制及如何優(yōu)化”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對“Linux讀寫機(jī)制及如何優(yōu)化”知識都有一定的了解,大家如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI