Linux Page cache和Buffer cache

free 命令常用參數

free 命令用來查看內存使用狀況,常用參數如下:

  • -h human-readable 格式打印
  • -w 把 cache & buffer 分開打印
  • -t show total for RAM + swap

free 結果指標剖析

centos6中,cache,buffers是分開的,7以後就合併了,cache/buffers

[root@10-23-220-95 ~]# free -hwt
              total        used        free      shared     buffers       cache   available
Mem:           7.6G        2.0G        3.3G        384M          0B        2.3G        4.9G
Swap:          511M        114M        397M
Total:         8.1G        2.1G        3.7G

Mem total 表示總計可用的物理內存大小

used 表示分配給進程的內存大小

free 未使用的內存大小

cache/buffers 是操作系統用來做緩存的內存佔用,未被使用的內存不能白白浪費,操作系統會拿它用作緩存以此提升性能

total = used + free + cache/buffers。當 free 內存被用完後,cache/buffers 會釋放一些供應用程序使用,所以 available (可用內存空間)要比 free 大一些。

Swap 是磁盤上劃分出來供內存使用的空間,經常不用的東西沒必要放在內存裏,可以把它置換到外存中,需要的時候再加載的內存。

buffers/cache 進一步理解

當我們使用 free -th -w 查看主機內存信息的時候,常會發現 buffers/cache 佔了許多內存空間。這些佔用是用來做什麼的呢?什麼時候我需要擴內存了呢?

其實,buffers/cache 用掉的空間是用來做磁盤頁緩存的,它使得系統運轉更加快速。除了使得新手迷惑以外,沒有其他任何弊端。buffers/cache 不會與應用程序爭搶內存空間,只要應用程序需要等多的內存,它就把用來做磁盤頁緩存的內存段歸還回去,給到應用程序使用

什麼時候開始真正小心內存不夠用了?

  1. available memory 接近於 0
  2. swap used 增長或者波動
  3. dmesg | grep oom-killer 能夠查看到 OutOfMemory-killer 在工作

shared memory 的理解

root@cloud:~ # free -t
              total        used        free      shared  buff/cache   available
Mem:      131106128     6740848   113822952     1376104    10542328   122002484
Swap:             0           0           0
Total:    131106128     6740848   113822952

通過 free 的輸出可以看到,有一列 shared 項。free 命令的信息來源是 /proc/meminfo,shared 列的數據來自於 Shmem 部分。

root@cloud:~ # cat /proc/meminfo  | grep Shmem
Shmem:           1376104 kB
ShmemHugePages:        0 kB
ShmemPmdMapped:        0 kB

shared memory 統計的是被 tmpfs 所使用的內存大小。我們可以通過 df -t 來查看 tmpfs 所站的空間大小

root@cloud:~ # df -T | grep tmpfs
udev           devtmpfs   65538520        0   65538520   0% /dev
tmpfs          tmpfs      13110616  1375724   11734892  11% /run
tmpfs          tmpfs      65553064      340   65552724   1% /dev/shm
tmpfs          tmpfs          5120        0       5120   0% /run/lock
tmpfs          tmpfs      65553064        0   65553064   0% /sys/fs/cgroup
shm            tmpfs         65536        0      65536   0% /data/docker-data/containers/6c626b670a9f9f6fe05f65a29c3f4ea223814dc39ca5416547a1e405f64c715c/mounts/shm
shm            tmpfs         65536        0      65536   0% /data/docker-data/containers/2ca280f90cab45f8249a7c8b0959b7cf4f62da5ccf29c3f41148df4fe92362f2/mounts/shm
shm            tmpfs         65536        0      65536   0% /data/docker-data/containers/3a6ed95e443e72b2821bc68932e06f6cf18bb7bbf21b71f50bb59b405857e28c/mounts/shm
shm            tmpfs         65536        0      65536   0% /data/docker-data/containers/d4c079af0ac5ec2e5faaa476d46baba8971729f44e9090a383ce9b4d2032d69c/mounts/shm
tmpfs          tmpfs      13110612        0   13110612   0% /run/user/0

如果我們把 tmpfs Used 列數字加起來,會發現和 free 中 shared 基本相等(因爲這個數據是動態一直在變化的)。那麼什麼是 tmpfs 呢?

tmpfs 是一個完全存在於內存裏的文件系統,和其他內存數據一樣,一切都是臨時數據,重啓機器後會丟失。tmpfs 的掛載和其他磁盤掛載類似,也可以在 /etc/fstab 內配置。

扇區sector

硬盤的讀寫以扇區爲基本單位。磁盤上的每個磁道被等分爲若干個弧段,這些弧段稱之爲扇區。硬盤的物理讀寫以扇區爲基本單位。通常情況下每個扇區的大小是 512 字節。linux 下可以使用 fdisk -l 瞭解扇區大小:

$ sudo /sbin/fdisk -l
Disk /dev/sda: 20 GiB, 21474836480 bytes, 41943040 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x7d9f5643

其中 Sector size,就是扇區大小,本例中爲 512 bytes。

扇區是磁盤物理層面的概念,操作系統是不直接與扇區交互的,而是與多個連續扇區組成的磁盤塊交互。由於扇區是物理層面的概念,所以無法在系統中進行大小的更改。

2009年後,硬盤廠商開始發佈4KB字節扇區的硬盤了,4KB扇區硬盤已經在消費級市場廣泛應用。但是同一塊硬盤上的扇區大小一定是一致的

塊/簇 IO Block

文件系統讀寫數據的最小單位,也叫磁盤簇。window系統叫簇,Linux叫塊,是操作系統虛擬出來的邏輯概念,扇區是磁盤最小的物理存儲單元,操作系統將相鄰的扇區組合在一起,形成一個塊,對塊進行管理。每個磁盤塊可以包括 2、4、8、16、32 或 64 個扇區。磁盤塊是操作系統所使用的邏輯概念,而非磁盤的物理概念。磁盤塊的大小可以通過命令 stat /boot 來查看:

$ sudo stat /boot
  File: /boot
  Size: 4096        Blocks: 8          IO Block: 4096   directory
Device: 801h/2049d  Inode: 655361      Links: 3
Access: (0755/drwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2019-07-06 20:19:45.487160301 +0800
Modify: 2019-07-06 20:19:44.835160301 +0800
Change: 2019-07-06 20:19:44.835160301 +0800
 Birth: -

其中 IO Block 就是磁盤塊大小,本例中是 4096 Bytes,一般也是 4K。

爲了更好地管理磁盤空間和更高效地從硬盤讀取數據,操作系統規定一個磁盤塊中只能放置一個文件,因此文件所佔用的空間,只能是磁盤塊的整數倍,那就意味着會出現文件的實際大小,會小於其所佔用的磁盤空間的情況。

img

test2.txt是一個只包含一個字母的文本文檔。它的理論大小是一個字節,但是由於系統的磁盤塊大小是4KB(文件的最小存儲大小單位),所以test2.txt佔據的磁盤實際空間是4KB

操作系統不能對磁盤扇區直接尋址操寫,主要原因是扇區數量龐大,因此纔將多個連續扇區組合一起操作。磁盤塊的大小是可以通過blockdev命令更改的。

頁 page

內存的最小存儲單位。頁的大小通常爲磁盤塊大小的 2^n 倍,可以通過命令 getconf PAGE_SIZE 來獲取頁的大小:

$sudo getconf PAGE_SIZE
4096

本例中爲 4096 Bytes,與磁盤塊大小一致。

總結兩個邏輯單位:

  • 頁,內存操作的基本單位
  • 磁盤塊,磁盤操作的基本單位

Page Cache

Page Cache以Page爲單位,緩存文件內容。緩存在Page Cache中的文件數據,能夠更快的被用戶讀取。同時對於帶buffer的寫入操作,數據在寫入到Page Cache中即可立即返回,而不需等待數據被實際持久化到磁盤,進而提高了上層應用讀寫文件的整體性能。

Buffer Cache

磁盤的最小數據單位爲sector,每次讀寫磁盤都是以sector爲單位對磁盤進行操作。

sector大小跟具體的磁盤類型有關,有的爲512Byte, 有的爲4K Bytes。無論用戶是希望讀取1個byte,還是10個byte,最終訪問磁盤時,都必須以sector爲單位讀取,如果裸讀磁盤,那意味着數據讀取的效率會非常低。

同樣,如果用戶希望向磁盤某個位置寫入(更新)1個byte的數據,他也必須整個刷新一個sector,言下之意,則是在寫入這1個byte之前,我們需要先將該1byte所在的磁盤sector數據全部讀出來,在內存中,修改對應的這1個byte數據,然後再將整個修改後的sector數據,一口氣寫入磁盤。

爲了降低這類低效訪問,儘可能的提升磁盤訪問性能,內核會在磁盤sector上構建一層緩存,他以sector的整數倍力度單位(block),緩存部分sector數據在內存中,當有數據讀取請求時,他能夠直接從內存中將對應數據讀出。當有數據寫入時,他可以直接再內存中直接更新指定部分的數據,然後再通過異步方式,把更新後的數據寫回到對應磁盤的sector中。這層緩存則是塊緩存Buffer Cache。

Page cache與Buffer Cache作用

page cache :頁緩存,負責緩存邏輯數據。

buffer cache : 塊緩存,負責緩存物理數據。

CacheBuffer是我們容易混淆的內存概念,Cache名爲緩存,Buffer名爲緩衝。

CacheBuffer的出現就是爲了彌補高速設備和低速設備之間的矛盾而設立的中間層

Cache會將低速設備中常被訪問的數據緩存起來,當高速設備需要再次訪問這些數據時,會命中Cache中的數據,以減少對低速設備的訪問。

Buffer用於緩和高速設備要把數據回寫到低速設備時帶來的衝擊,當數據量比較大時,Buffer能將數據分割成合適的大小,分批迴寫到磁盤;當數據量比較小的時候,Buffer能將分散的寫操作集中進行,減少磁盤碎片和硬盤的反覆尋道,通過“流量整形”提高系統性能。

讀取數據具體流程是:先去讀取buffer cache,如果cache空間不夠,會通過一定的策略將一些過時或多次未被訪問的buffer cache清空。程序在下一次訪問磁盤時首先查看是否在buffer cache找到所需塊,命中可減少訪問磁盤時間。不命中時需重新讀入buffer cache。

Page cache和Buffer cache的區別

磁盤的操作有邏輯級(文件系統)和物理級(磁盤塊),這兩種Cache就是分別緩存邏輯和物理級數據的。

假設我們通過文件系統操作文件,那麼文件將被緩存到Page Cache,如果需要刷新文件的時候,Page Cache將交給Buffer Cache去完成,因爲Buffer Cache就是緩存磁盤塊的。

也就是說,直接去操作文件,那就是Page Cache區緩存,用dd等命令直接操作磁盤塊,就是Buffer Cache緩存的東西。

Page cache實際上是針對文件系統的,是文件的緩存,在文件層面上的數據會緩存到page cache。文件的邏輯層需要映射到實際的物理磁盤,這種映射關係由文件系統來完成。當page cache的數據需要刷新時,page cache中的數據交給buffer cache,但是這種處理在2.6版本的內核之後就變的很簡單了,沒有真正意義上的cache操作。

Buffer cache是針對磁盤塊的緩存,也就是在沒有文件系統的情況下,直接對磁盤進行操作的數據會緩存到buffer cache中,例如,文件系統的元數據都會緩存到buffer cache中。

簡單說來,page cache用來緩存文件數據,buffer cache用來緩存磁盤數據。在有文件系統的情況下,對文件操作,那麼數據會緩存到page cache,如果直接採用dd等工具對磁盤進行讀寫,那麼數據會緩存到buffer cache。

Buffer(Buffer Cache)以塊形式緩衝了塊設備的操作,定時或手動的同步到硬盤,它是爲了緩衝寫操作然後一次性將很多改動寫入硬盤,避免頻繁寫硬盤,提高寫入效率。

Cache(Page Cache)以頁面形式緩存了文件系統的文件,給需要使用的程序讀取,它是爲了給讀操作提供緩衝,避免頻繁讀硬盤,提高讀取效率。

圖解Page Cache與Buffer Cache

程序讀取的文件數據保留在Page Cache(頁面緩存)中,以便將來讀取時重用。如第一次使用findgrep命令時速度比較慢,再次執行就非常快。

Page Cache中的數據需要刷新時,Page Cache中的數據會交給Buffer Cache,而Buffer Cache中的數據會定時刷新到磁盤中,也可通過sync命令將緩衝區裏的數據寫入磁盤。如果突然斷電,Buffer Cache沒來得及寫入到磁盤中,那麼就會發生數據丟失。

img

在Linux 2.4以前page cache和buffer cache是兩個獨立的緩存,Linux 2.4開始buffer cache不再是一個獨立的緩存,如下圖所示的那樣,它被包含在page cache中,通過page cache來實現。

img

Page Cache、Buffer Cache兩者融合

介於上述Page Cache、Buffer Cache分離設計的弊端,Linux-2.4版本中對Page Cache、Buffer Cache的實現進行了融合,融合後的Buffer Cache不再以獨立的形式存在,Buffer Cache的內容,直接存在於Page Cache中,同時,保留了對Buffer Cache的描述符單元:buffer_head。

img

兩者的關係已經相互融合如下圖所示:

img

一個文件的PageCache(page),通過 buffers 字段能夠非常快捷的確定該page對應的buffer_head信息,進而明確該page對應的device, block等信息。

總結

pageCache緩衝了讀數據操作,如果要寫入數據,pageCache會將數據傳遞給bufferCache,通過bufferCache緩衝寫數據操作。

參考:

linux free 命令 查看內存使用情況

linux 內存查看之 free 命令

Linux系統中的Page cache和Buffer cache

Linux內核Page Cache和Buffer Cache關係及演化歷史

三分鐘增強內功!Linux中的Buffer與Cache

計算機存儲術語: 扇區,磁盤塊,頁

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章