Linux 內(nèi)核的緩存簡(jiǎn)介

緩存機(jī)制介紹

Linux 系統(tǒng)中,為了提高文件系統(tǒng)的讀寫性能1,內(nèi)核會(huì)利用一部分內(nèi)存(相當(dāng)大的剩余內(nèi)存)分配緩存區(qū),用于緩存系統(tǒng)操作和數(shù)據(jù)。當(dāng)核外數(shù)據(jù)需要寫入磁盤時(shí),該 IO 請(qǐng)求將會(huì)被緩存起來,等到一個(gè)合適的時(shí)機(jī)一并寫入到后端磁盤,這就是回寫緩存;當(dāng)核外需要讀取磁盤數(shù)據(jù)時(shí),此 IO 讀請(qǐng)求將會(huì)一次性讀取更多的數(shù)據(jù)保留到特定的緩存區(qū)域,這種預(yù)測(cè)下一次讀取數(shù)據(jù)的位置方式叫做預(yù)讀,他讀到的數(shù)據(jù)也將保存到緩存中。他們都可以稱之為緩存,緩存的核心是算法,后面的章節(jié)會(huì)稍微介紹一下當(dāng)前 Linux 主流采用的緩存核心算法。緩存的好處顯而易見,那么可以合并多個(gè) IO 請(qǐng)求,從而減少 CPU 上下文的切換以及減少堆棧調(diào)用,同時(shí)可以提高磁盤訪問效率。由于緩存的存在,內(nèi)核的代碼和數(shù)據(jù)結(jié)構(gòu)不必單一的從磁盤讀取,也不必一定強(qiáng)制要求立刻寫入磁盤,因此頁(yè)面緩存可能是下面這些類型:

  • 普通文件數(shù)據(jù)的頁(yè)
  • 含有目錄的頁(yè)
  • 含有直接從塊設(shè)備文件(跳過文件系統(tǒng)層)讀取的數(shù)據(jù)頁(yè)
  • 含有用戶態(tài)進(jìn)程數(shù)據(jù)的頁(yè),但頁(yè)中數(shù)據(jù)已被交換到磁盤
  • 數(shù)據(jù)特殊文件系統(tǒng)的頁(yè),比如進(jìn)程間通信中的特殊文件系統(tǒng) shm

下圖是塊設(shè)備的 I/O 操作流程,從圖中可以看出具體的文件系統(tǒng)(如 ext4 等)負(fù)責(zé)文件在 Cache 和存儲(chǔ)設(shè)備間交換數(shù)據(jù),位于具體文件系統(tǒng)之上的虛擬文件系統(tǒng) VFS 負(fù)責(zé)在應(yīng)用程序和文件 Cache 之間通過 read/write 等接口交換數(shù)據(jù)。

頁(yè)面 Cache 中每頁(yè)所包含的數(shù)據(jù)是屬于某個(gè)文件(準(zhǔn)確的說應(yīng)該是文件的 inode),所有的 read/write 都依賴于頁(yè)面 Cache,當(dāng)然,你設(shè)置了 O_DIRECT 標(biāo)志的話,頁(yè)面 Cache 就會(huì)被跳過2。

查看當(dāng)前的系統(tǒng)的緩存區(qū)和內(nèi)存使用情況

上面的命令看得出,該系統(tǒng)存在 32G 的內(nèi)存,已使用了 280M,剩余 2450M。其中 buff/cache 一共占據(jù)了 29409M,也就是說其實(shí)現(xiàn)在的剩余空間之所以只剩下不到 2G 就是剩下的大約 29G 都被緩存占據(jù)了,不過該命令的最后一段給出的 available 告訴的就是當(dāng)前系統(tǒng)可用內(nèi)存還剩下 31G 左右,說明 buff/cache 是可以被回收掉的,他們也是屬于可用內(nèi)存的一種。

緩存區(qū) buffers 和 caches 的區(qū)別

之前一直不太懂緩存區(qū)為何還分為 buffer 和 cache 段,查了很多資料,而且不太統(tǒng)一,甚至連內(nèi)核下的 Document 下的描述也不是很清晰,而且我還覺得是不是寫錯(cuò)了,綜合各種渠道來源的資料,我貼出一種比較認(rèn)可的說法。

buffers 是用來給塊設(shè)備使用的緩存區(qū),他只記錄文件系統(tǒng)的 metadata 以及 tacking in-flight pages;cached 是用來給文件做緩沖。意思就是說,buffers 用來存儲(chǔ)目錄里面有什么內(nèi)容和權(quán)限,而 cached 用來記憶我們打開的文件。我們稍微來做一個(gè)實(shí)驗(yàn),還是之前的那一臺(tái)機(jī)器,我們觀察 /proc/meminfo 下面的相關(guān)選項(xiàng)的數(shù)據(jù)變化。

[root@localhost ~]# cat /proc/meminfo
Buffers:          414412 kB
Cached:         29666920 kB

這是在當(dāng)前什么都不做的情況下的一個(gè)內(nèi)存使用情況,我省略了其他的部分,請(qǐng)僅僅關(guān)注 buffers 和 cached 這兩個(gè)部分。此時(shí)我嘗試 ls 觀察一個(gè)目錄,然后再 cat meminfo 這個(gè)文件,現(xiàn)在請(qǐng)看:

[root@localhost ~]# ls /
bin  boot  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin

[root@localhost ~]# cat /proc/meminfo
Buffers:          414420 kB
Cached:         29666920 kB

可不可以看得到,cached 并沒有發(fā)生變化,僅僅只是 buffers 字段數(shù)據(jù)增加了,說明在查看目錄的時(shí)候,buffers 區(qū)域保存了這個(gè)目錄的一些信息,所以他占用了大約 8kb 的內(nèi)容,這里的頁(yè)大小為 4kb,所以應(yīng)該說是剛剛的操作導(dǎo)致 buffers 擴(kuò)展了 2 個(gè)頁(yè),所以 buffers 這個(gè)很好理解,那么我們?cè)賮砜纯?cached 的作用。

首先我們清理掉整個(gè)系統(tǒng)的非在線緩存(沒有正在被處理的緩存,可以被回收的緩存),echo 1 > /proc/sys/vm/drop_caches,然后讀取當(dāng)前的 meminfo 信息

[root@localhost ~]# echo 1 > /proc/sys/vm/drop_caches

[root@localhost ~]# cat /proc/meminfo
Buffers:            1080 kB
Cached:            58740 kB

然后執(zhí)行文件讀取,再觀察 meminfo

[root@localhost ~]# dd if=/root/file1 of=/dev/null

[root@localhost ~]# cat /proc/meminfo
Buffers:            1080 kB
Cached:            64168 kB

cached 字段發(fā)生了改變,是不是很清晰,當(dāng)然,不僅僅是我演示的讀文件會(huì)改變 cached 字段的大小,寫同樣也會(huì)增加或者改變這個(gè)字段的大小3,這里就不進(jìn)行演示了。

釋放緩存內(nèi)存的方法

上面稍微提到了釋放緩存區(qū)的一種方式,現(xiàn)在可以全面的總結(jié)如何回收緩存。

清理 pagecache(頁(yè)面緩存)

[root@localhost ~]# echo 1 > /proc/sys/vm/drop_caches
或者
[root@localhost ~]# sysctl -w vm.drop_caches=1

清理 dentries(目錄緩存)和 inodes

[root@localhost ~]# echo 2 > /proc/sys/vm/drop_caches
或者
[root@localhost ~]# sysctl -w vm.drop_caches=2

清理 pagecache、dentries 和 inodes

[root@localhost ~]# echo 3 > /proc/sys/vm/drop_caches
或者
[root@localhost ~]# sysctl -w vm.drop_caches=3

上面三種都是可以臨時(shí)釋放緩存的方法,要想永久釋放緩存,需要在 /etc/sysctl.conf 中配置:vm.drop_caches=1/2/3,然后執(zhí)行 sysctl -p 讓設(shè)置生效即可!另外,可以使用 sync 命令來清理文件系統(tǒng)緩存,他還會(huì)清理掉僵尸(zombie)對(duì)象和他們所占用的內(nèi)存。

vfs_cache_pressure 和 min_free_kbytes

從名字就可以看得出這兩個(gè)接口的意義,一個(gè)是用來控制 cache 的回收傾向,一個(gè)是控制最小的可用 free 內(nèi)存的大小,綜合上面提到的 free 內(nèi)存的計(jì)算方式,我們知道 free 內(nèi)存就是可以交給其他程序使用的內(nèi)存,這里不包括緩存,也就是說,設(shè)置這個(gè) min_free_kbytes 的作用主要是為了防止緩存將所有的內(nèi)存全部耗盡,而導(dǎo)致其他程序無法申請(qǐng)到內(nèi)存而崩潰4。

vfs_cache_pressure 是用來表示內(nèi)核在回收的時(shí)候,對(duì)于 dentries 和 inodes 內(nèi)存的回收傾向,默認(rèn)值為 100,表示會(huì)根據(jù) pagecache 和 swapcache 給出一個(gè)合適的百分比;降低該值,將導(dǎo)致內(nèi)核傾向于更多的保留 dentries 和 inodes 的緩存內(nèi)存;提高該值,將導(dǎo)致內(nèi)核更為激進(jìn)的回收掉緩存。

in_free_kbytes 前文已經(jīng)將他的作用稍微說明了一次,這里主要講一講他的默認(rèn)值,在內(nèi)核源碼中,他的定義位于 mm/page_alloc.c 文件中。

/*
  * Initialise min_free_kbytes.
  *
  * For small machines we want it small (128k min).  For large machines
  * we want it large (64MB max).  But it is not linear, because network
  * bandwidth does not increase linearly with machine size.  We use
  *
  *      min_free_kbytes = 4 * sqrt(lowmem_kbytes), for better accuracy:
  *      min_free_kbytes = sqrt(lowmem_kbytes * 16)
  *
  * which yields
  *
  * 16MB:        512k
  * 32MB:        724k
  * 64MB:        1024k
  * 128MB:       1448k
  * 256MB:       2048k
  * 512MB:       2896k
  * 1024MB:      4096k
  * 2048MB:      5792k
  * 4096MB:      8192k
  * 8192MB:      11584k
  * 16384MB:     16384k
  */

通過一系列的運(yùn)算,得到的如上面的表對(duì)應(yīng)的一個(gè)值,左列為當(dāng)前系統(tǒng)的內(nèi)存大小,后面為 min_free_kbytes 的大小。

原文

https://www.byteisland.com/linux-%e5%86%85%e6%a0%b8%e7%9a%84%e7%bc%93%e5%ad%98%e7%ae%80%e4%bb%8b/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容