16-基礎篇:怎么理解內存中Buffer和Cache?






free數據的來源

# 注意不同版本的free輸出可能會有所不同
# centos7版本
[root@local_sa_192-168-1-6 ~]# free
       total   used    free     shared  buff/cache  available
Mem:   8169348 263524  6875352  668     1030472     7611064
Swap:  0       0       0

Buffer和Cache不太好區分
Buffer是緩沖區,而Cache是緩存,兩者都是數據在內存中的臨時存儲
用man命令查詢free的文檔,就可以找到對應指標的詳細說明

buffers
    Memory used by kernel buffers (Buffers in /proc/meminfo)
cache 
    Memory used by the page cache and slabs (Cached and SReclaimable in /proc/
buff/cache
    Sum of buffers and cache

Buffers是內核緩沖區用到的內存,對應的是/proc/meminfo中的Buffers值
Cache是內核頁緩存和Slab用到的內存,對應的是/proc/meminfo中的Cached與SReclaimable之和



proc文件系統

/proc是Linux內核提供的一種特殊文件系統,是用戶跟內核交互的接口
用戶可以從/proc中查詢內核的運行狀態和配置選項, 查詢進程的運行狀態、統計數據等
也可以通過/proc來修改內核的配置

proc文件系統同時也是很多性能工具的最終數據來源
比如free ,就是通過讀取/proc/meminfo ,得到內存的使用情況

執行man proc,可以得到proc文件系統的詳細文檔

Buffers %lu
    Relatively temporary storage for raw disk blocks that shouldn't get tremendously lar
Cached %lu
    In-memory cache for files read from the disk (the page cache). Doesn't include SwapC
...
SReclaimable %lu (since Linux 2.6.19)
    Part of Slab, that might be reclaimed, such as caches.
SUnreclaim %lu (since Linux 2.6.19)
    Part of Slab, that cannot be reclaimed on memory pressure.

通過這個文檔,可以看到

  1. Buffers是對原始磁盤塊的臨時存儲,也就是用來緩存磁盤的數據,通常不會特別大 (20MB 左右)
    這樣,內核就可以把分散的寫集中起來,統一優化磁盤的寫入,比如可以把多次小的寫合並成單次大的寫等等
  2. Cached是從磁盤讀取文件的頁緩存,也就是用來緩存從文件讀取的數據
    這樣,下次訪問這些文件數據時,就可以直接從內存中快速獲取,而不需要再次訪問緩慢的磁盤
  3. SReclaimable是Slab的一部分。Slab包括兩部分,其中的可回收部分,用SReclaimable 記錄
    而不可回收部分,用SUnreclaim 記錄

產生的疑問:

  1. Buffer的文檔沒有提到這是磁盤讀數據還是寫數據的緩存,而在很多網絡搜索的結果中都會提到Buffer只是對將要寫入磁盤數據的緩存。
    那反過來說,它會不會也緩存從磁盤中讀取的數據呢?
  2. Cache是對從文件讀取數據的緩存,那么它是不是也會緩存寫文件的數據呢?


案例

准備

實驗環境
# 服務端(192.168.1.6)
配置:2CPU,4G內存,centos7.6_64     
預先安裝docker、sysstat、等工具(yum install sysstat -y)

為了減少緩存的影響,運行下面的命令來清理系統緩存:
# 清理文件頁、目錄項、Inodes 等各種緩存
[root@local_sa_192-168-1-6 ~]# echo 3 > /proc/sys/vm/drop_caches

這里的/proc/sys/vm/drop_caches,就是通過proc文件系統修改內核行為的一個示例,
寫入3表示清理文件頁、目錄項、Inodes等各種緩存。


場景 1:磁盤和文件寫案例

文件寫的案例

  1. 在第一個終端,運行 vmstat 命令

    [root@local_sa_192-168-1-6 ~]# vmstat 1
    procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
     r  b   swpd   free   buff  cache     si   so    bi    bo  in   cs   us  sy  id   wa st
     1  0      0 3030208  12    318020    0    0     0     0   7    5    0   0   100  0  0
     0  0      0 3030208  12    318020    0    0     0     0   61   102  0   0   100  0  0
     0  0      0 3030208  12    318020    0    0     0     0   75   107  1   0   99   0  0
     0  0      0 3030208  12    318020    0    0     0     0   37   69   0   0   100  0  0
     0  0      0 3030208  12    318020    0    0     0     0   46   75   0   0   100  0  0
    

​ buff和cache就是前面看到的Buffers和Cache,單位是KB

​ bi和bo則分別表示塊設備讀取和寫入的大小,單位為塊 / 秒。因為Linux中塊的大小是1KB,所以這個單位也就等價於KB/s

​ 正常情況下,空閑系統中,這幾個值在多次結果中一直保持不變


  1. 到第二個終端執行dd命令,通過讀取隨機設備,生成一個500MB大小的文件

    [root@local_sa_192-168-1-6 ~]# dd if=/dev/urandom of=/tmp/file bs=1M count=500
    記錄了500+0 的讀入
    記錄了500+0 的寫出
    524288000字節(524 MB)已復制,2.05113 秒,256 MB/秒
    

    同時,觀察第一個終端,觀察Buffer和Cache的變化情況

    [root@local_sa_192-168-1-6 ~]# vmstat 1
    procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
     r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
     0  0      0 3023392     12 318244    0    0     0     0   63  114  0  0 99  0  0
     1  0      0 3000776     12 340384    0    0    76     0  216  187  0  5 94  1  0
     1  0      0 2743380     12 597688    0    0     0     0 1067  118  0 50 50  0  0
     0  1      0 2496184     12 845864    0    0     0 97796 1402  415  0 48  8 41  2
     0  1      0 2496264     12 845832    0    0     0 32768  179  118  0  1 50 49  0
     0  1      0 2496296     12 845800    0    0     0 16384  122  117  0  0 50 50  0
     0  1      0 2496168     12 845932    0    0     0 49152  248   90  0  1 50 49  0
     0  0      0 2496712     12 845340    0    0     0 16896  256  102  0  1 83 16  0
    

    通過觀察vmstat的輸出,我們發現,在dd命令運行時, Cache在不停地增長,而Buffer基本保持不變

    再進一步觀察 I/O 的情況

    1. 在Cache剛開始增長時,塊設備I/O很少,bi只出現了一次76KB/s
      而過一段時間后,才會出現大量的塊設備寫,比如bo變成了 97796
    2. 當dd命令結束后,Cache不再增長,但塊設備寫還會持續一段時間
      並且,多次 I/O 寫的結果加起來,才是dd要寫的500M的數據

    Cache 對文件的寫入會緩存


磁盤寫的案例

注意:下面的命令對環境要求很高,需要系統配置多塊磁盤,並且磁盤分區/dev/sdb1還要處於未使用狀態
如果只有一塊磁盤,千萬不要嘗試,否則將會對你的磁盤分區造成損壞

清理緩存后,向磁盤分區/dev/sdb1寫入2GB的隨機數據

# 首先清理緩存
[root@local_sa_192-168-1-6 ~]# echo 3 > /proc/sys/vm/drop_caches
# 然后運行 dd 命令向磁盤分區 /dev/sdb1 寫入 2G 數據
[root@local_sa_192-168-1-6 ~]# dd if=/dev/urandom of=/dev/sdb1 bs=1M count=2048

同時,觀察內存和I/O的變化情況

[root@local_sa_192-168-1-6 ~]# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free     buff     cache    si  so  bi   bo     in  cs us sy id wa st
 1  0   0      7584780  153592   97436    0   0   684  0      31  423 1 48 50 2  0
 1  0   0      7418580  315384   101668   0   0   0    0      32  144 0 50 50 0  0
 1  0   0      7253664  475844   106208   0   0   0    0      20  137 0 50 50 0  0
 1  0   0      7093352  631800   110520   0   0   0    0      23  223 0 50 50 0  0
 1  1   0      6930056  790520   114980   0   0   0    12804  23  168 0 50 42 9  0
 1  0   0      6757204  949240   119396   0   0   0    183804 24  191 0 53 26 21 0
 1  1   0      6591516  1107960  123840   0   0   0    77316  22  232 0 52 16 33 0

從這里可以看到,雖然同是寫數據,寫磁盤跟寫文件的現象還是不同的
寫磁盤時(也就是bo大於0時),Buffer和Cache都在增長,但顯然Buffer的增長快得多
這說明,寫磁盤用到了大量的Buffer。


小結

對比兩個案例,可以知道,寫文件時會用到Cache緩存數據,而寫磁盤則會用到Buffer來緩存數據
所以,雖然文檔上只提到,Cache是文件讀的緩存,但實際上,Cache也會緩存寫文件時的數據



場景 2:磁盤和文件讀案例

文件讀的案例

清理緩存后,從文件/tmp/file中,讀取數據寫入空設備

# 首先清理緩存
[root@local_sa_192-168-1-6 ~]# echo 3 > /proc/sys/vm/drop_caches
# 運行 dd 命令讀取文件數據
[root@local_sa_192-168-1-6 ~]# dd if=/tmp/file of=/dev/null

然后,觀察內存和 I/O 的變化情況

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 1 0 7724164 2380 110844 0 0 16576 0 62 360 2 2 76 21 0
0 1 0 7691544 2380 143472 0 0 32640 0 46 439 1 3 50 46 0
0 1 0 7658736 2380 176204 0 0 32640 0 54 407 1 4 50 46 0
0 1 0 7626052 2380 208908 0 0 32640 40 44 422 2 2 50 46 0

觀察vmstat的輸出,發現讀取文件時(也就是 bi 大於 0 時),Buffer保持不變
而Cache則在不停增長。這跟查到的定義“Cache 是對文件讀的頁緩存”是一致的


磁盤讀的案例

清理緩存后,從磁盤分區/dev/sda1中讀取數 據,寫入空設備

# 首先清理緩存
[root@local_sa_192-168-1-6 ~]# echo 3 > /proc/sys/vm/drop_caches
# 運行 dd 命令讀取文件
[root@local_sa_192-168-1-6 ~]# dd if=/dev/sda1 of=/dev/null bs=1M count=1024

然后,觀察內存和 I/O 的變化情況

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 7225880 2716 608184 0 0 0 0 48 159 0 0 100 0 0
 0 1 0 7199420 28644 608228 0 0 25928 0 60 252 0 1 65 35 0
 0 1 0 7167092 60900 608312 0 0 32256 0 54 269 0 1 50 49 0
 0 1 0 7134416 93572 608376 0 0 32672 0 53 253 0 0 51 49 0
 0 1 0 7101484 126320 608480 0 0 32748 0 80 414 0 1 50 49 0

觀察vmstat的輸出,發現讀磁盤時(也就是 bi 大於 0 時),Buffer和Cache都在增長,但顯然Buffer的增長快很多
這說明讀磁盤時,數據緩存到了Buffer中



結論

Buffer 既可以用作“將要寫入磁盤數據的緩存”,也可以用作“從磁盤讀取數據的緩存”

Cache 既可以用作“從文件讀取數據的頁緩存”,也可以用作“寫文件的頁緩存”

Buffer是對磁盤數據的緩存,而Cache是文件數據的緩存,它們既會用在讀請求中,也會用在寫請求中



小結

Buffer 和 Cache 分別緩存磁盤和文件系統的讀寫數據

  1. 從寫的角度來說,不僅可以優化磁盤和文件的寫入,對應用程序也有好處,應用程序可以在數據真正落盤前,就返回去做其他工作
  2. 從讀的角度來說,既可以加速讀取那些需要頻繁訪問的數據,也降低了頻繁 I/O 對磁盤的壓力


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM