作为Linux系统使用者,平时最关心的事情之一就是监控服务器的内存可用大小了。内存作为不可压缩资源,一旦超出使用就会导致应用出现OOM( Out Of Memory),某些应用就会强行被系统干掉。虽然可以调整应用的优先级让系统优先考虑干掉别的应用,但是出现OOM本身就说明了资源的不充足。
所以监控内存,跟查看内存剩余大小是很基础的一环。
查看内存可用大小的指令有很多,比如:
free -m
或者
vmstat
或者
cat /proc/meminfo
都可以查看当前可用的内存大小
free -m
free命令由procps.*.rpm提供(在Redhat系列的OS上)。free命令的所有输出值都是从/proc/meminfo中读出
在centos6中显示
total used free shared buffers cached
Mem: 32109 31854 254 0 162 17294
-/+ buffers/cache: 14398 17710
Swap: 18431 1633 16798
在centos7中显示
total used free shared buff/cache available
Mem: 1839 1221 77 3 540 445
Swap: 4095 0 4095
我们可以看到两个系统版本的free -m 显示的内容是有差别的。
先解释一下各列的意思:
total: 就是系统总共的内存值
used: 系统已经使用的内存值
free:系统剩余未使用的内存
shared:系统用来共享的内存值
在centos6中,
(-/+ buffers/cache):
(-buffers/cache) used内存数:(指的第一部分Mem行中的used – buffers – cached)
(+buffers/cache) free内存数: (指的第一部分Mem行中的free + buffers + cached)
在centos7中,系统剩余可用内存就在Mem那行中available那列的值
vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
3 0 0 79456 124200 429484 0 0 1 6 0 0 1 0 99 0 0
在centos6跟centos7中显示都一样
这里我们只关注memory部分
cat /proc/meminfo
MemTotal: 1883724 kB
MemFree: 72280 kB
MemAvailable: 448864 kB
Buffers: 124232 kB
Cached: 364804 kB
.
.
.
Slab: 64856 kB
从上面的例子看,其它内存部分都比较清晰,我们这里就重点讨论Buffer跟Cache。
从字面上来说,Buffer 是缓冲区,而 Cache 是缓存,两个指标都是数据在内存中的临时存储。
为了进一步清楚Buffers 跟Cache的意思,我们可以man free一下,得到以下解释:
cache Memory used by the page cache and slabs (Cached and Slab in /proc/meminfo)
buff/cache
Sum of buffers and cache
Buffers 是内核缓冲区用到的内存,对应的是 /proc/meminfo 中的 Buffers 值。
Cache 是内核页缓存和 Slab 用到的内存,对应的是 /proc/meminfo 中的 Cached 与 Slab 之和。
这里告诉我们的是这些数据都是来自/proc/meminfo ,但是具体的含义并没有说清楚。
这个时候我们通常情况下都会去百度或者谷歌一下,虽然大多数情况都可以找到一个答案。但是,筛查结果且不说耗费精力,也可能因为你的内核版本,性能工具版本的不同而有差别。而且可能因为博客作者不严谨,也是遇到问题,然后网上一查,没有核查,然后自己随手做了笔记,然后Po到网上当记录了。
那还有没有更简单,更准确的方法来查buffer跟cache呢?
上面的vmstat 跟free 其实都是读取/pro/meminfo文件的信息,既然在/pro/meminfo 中Buffers、Cache、Slab这几个指标不容易 理解,我们就继续往上查找proc文件系统,获取它们的定义。
/proc 是 Linux 内核提供的一种特殊文件系统,是用户跟内核交互的接口。比方说,用户可以从 /proc 中查询内核的运行状态和配置选项,查询进程的运行状态、统计数据等,当然,你也可以通过 /proc 来修改内核的配置。
执行man proc来查看文档
如果man proc时候报错:
No manual entry for proc
先yum 安装一下man-pages 包
yum install -y man-pages
然后继续执行man proc (文档很大,可以查找meminfo)
Relatively temporary storage for raw disk blocks that shouldn't get tremendously large (20MB or so).
Cached %lu
In-memory cache for files read from the disk (the page cache). Doesn't include SwapCached.
Slab %lu
In-kernel data structures cache.
通过文档我们看到
Cached 是从磁盘读取文件的页缓存,也就是用来缓存从文件读取的数据。
Slab 内核的数据结构缓存
这里我们可以清楚地看到三个指标的定义了。
但是在定义里没有说明Buffers是读还是写的临时存储,Cached定义中说是磁盘读取文件的缓存,是否可以写文件缓存呢?
网上有很多文章,都写Buffers是磁盘块的写缓存。
为了弄清楚这两个问题,可以用两个场景来说明展示。
首先,为了减少缓存的影响,先清理系统缓存。
# echo 3 > /proc/sys/vm/drop_caches
场景1:文件读写案例
先在一个终端那里执行vmstat命令
每隔1秒输出1组数据
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
2 0 0 77068 60624 496172 0 0 1 6 0 0 1 0 99 0 0
0 0 0 77068 60624 496152 0 0 0 0 573 1363 1 1 98 0 0
输出界面里, 内存部分的 buff 和 cache ,以及 io 部分的 bi 和 bo 是我们要关注的重点。
buff 和 cache 就是我们前面看到的 Buffers 和 Cache,单位是 KB。
bi 和 bo 则分别表示块设备读取和写入的大小,单位为块 / 秒。
因为 Linux 中块的大小是 1KB,所以这个单位也就等价于 KB/s。
正常情况下,空闲系统中这几个值在多次结果中一直保持不变。
然后再开一个终端,执行dd命令,生成一个文件。
dd if=/dev/urandom of=/tmp/test-file bs=1M count=500
然后回到第一个终端,看数据变化
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 515284 3828 114548 0 0 0 0 585 1365 2 1 97 0 0
0 0 0 515284 3828 114548 0 0 0 0 541 1317 1 0 99 0 0
14 0 0 506856 3832 121800 0 0 80 0 1211 878 0 71 28 1 0
12 0 0 495600 3840 133056 0 0 0 148 1334 652 0 100 0 0 0
11 0 0 484344 3840 144296 0 0 0 0 1388 684 1 99 0 0 0
13 0 0 475196 3840 153512 0 0 0 0 1254 623 0 100 0 0 0
14 0 0 463752 3840 164824 0 0 0 20520 1408 667 0 100 0 0 0
12 0 0 453612 3840 175080 0 0 0 0 1414 681 1 99 0 0 0
.
.
.
7 0 0 116636 3912 512012 0 0 4 20520 1150 639 1 99 0 0 0
10 0 0 105104 3912 523564 0 0 0 0 1436 689 0 100 0 0 0
2 0 0 95648 3912 533052 0 0 0 46080 1257 633 1 99 0 0 0
6 0 0 83992 3912 544620 0 0 0 0 1445 703 0 100 0 0 0
5 0 0 72460 3912 556172 0 0 0 0 1435 692 0 100 0 0 0
4 1 0 74980 2700 554852 0 0 0 28 1434 714 1 99 0 0 0
9 0 0 64468 2704 565300 0 0 4 20512 1465 721 0 100 0 0 0
通过vmstat的输出,在dd命令执行时,Cache在不停增长,而Buffer基本保持不变
进一步观察 I/O 的情况,你会看到,
在 Cache 刚开始增长时,块设备 I/O 很少,bi 只出现了一次 80 KB/s,bo 则只有一次 148KB。而过一段时间后,才会出现大量的块设备写,比如 bo 变成了20520。
当 dd 命令结束后,Cache 不再增长,但块设备写还会持续一段时间,并且,多次 I/O 写的结果加起来,才是 dd 要写的 500M 的数据。
测试完文件写案例,接着测试文件读案例
现在另外一个终端中执行
vmstat 1
然后在另外一个终端上执行
echo 3 > /proc/sys/vm/drop_caches
#运行dd命令读取文件数据
$ dd if=/tmp/test-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 0 0 519268 1136 107824 0 0 0 0 564 1347 0 1 99 0 0
0 0 0 519268 1144 107816 0 0 0 44 594 1395 2 1 97 0 0
2 1 0 503188 1292 124124 0 0 16428 0 626 1407 1 1 96 2 0
0 1 0 396676 1292 230572 0 0 106496 0 928 1458 4 12 0 84 0
0 1 0 290216 1292 337100 0 0 106496 0 911 1382 3 11 0 86 0
2 1 0 187668 1292 439500 0 0 102400 0 936 1406 3 13 0 84 0
0 1 0 97520 1292 529612 0 0 90112 0 876 1419 4 10 0 86 0
0 0 0 73264 384 554856 0 0 90492 16 940 1410 3 13 0 84 0
0 0 0 73268 388 554876 0 0 4 120 560 1343 2 0 98 0 0
0 0 0 73268 436 554880 0 0 48 0 604 1417 2 1 93 4 0
0 0 0 73144 436 554880 0 0 0 0 601 1441 1 1 98 0 0
观察 vmstat 的输出,会发现读取文件时(也就是 bi 大于 0 时),Buffer 保持不变,而 Cache 则在不停增长。这跟查到的定义“Cache 是对文件读的页缓存”是一致的。
从这两个案例中可以看到, Cache 是文件数据的缓存,既会用在读请求中,也会用在写请求中。
场景2:磁盘的读写案例
对磁盘的写,这个案例要求比较高,需要你的系统配置多块硬盘,并且磁盘分区还要处于未使用状态。因为会损坏磁盘分区。
echo 3 > /proc/sys/vm/drop_caches
# 然后运行dd命令向磁盘分区/dev/sdb4写入2G数据
$ dd if=/dev/urandom of=/dev/sdb4 bs=1M count=2048```
然后回到另外一个终端查看vmstat的状态
```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 3644696 24 52524 0 0 0 0 85 117 0 0 100 0 0
0 0 0 3644696 24 52524 0 0 0 0 77 103 0 0 100 0 0
1 0 0 3589948 52236 54736 0 0 1380 4 787 430 0 19 81 1 0
1 0 0 3452192 186380 58204 0 0 32 0 1720 603 1 50 50 0 0
1 0 0 3354724 281520 60720 0 0 0 0 1688 606 0 50 50 0 0
3 0 0 3277440 356692 62708 0 0 0 49156 1684 613 0 60 40 0 0
1 0 0 3213408 418828 64536 0 0 0 57340 1441 431 0 62 38 0 0
1 0 0 3160660 470288 65956 0 0 0 53248 1619 569 0 60 40 0 0
1 0 0 3109140 520204 67284 0 0 0 53248 1664 544 0 62 38 0 0
1 0 0 3057880 570380 68724 0 0 0 53248 1603 535 0 61 39 0 0
4 0 0 3007020 619612 69844 0 0 0 52412 1535 509 0 62 38 0 0
2 0 0 2974628 651344 70772 0 0 0 836 1560 603 0 42 58 0 0
.
.
.
2 0 0 1874952 1720932 100704 0 0 0 95744 915 213 1 99 0 0 0
1 0 0 1817940 1776680 102172 0 0 0 20076 1673 578 0 56 44 0 0
1 0 0 1744752 1847768 104128 0 0 64 0 1427 583 0 50 50 0 0
1 0 0 1679988 1910920 105908 0 0 0 0 1416 563 0 50 50 0 0
1 0 0 1610388 1978380 107892 0 0 0 0 1468 717 0 50 50 0 0
1 0 0 1539548 2047420 109856 0 0 0 0 1380 754 0 51 50 0 0
1 0 0 1498824 2086924 110888 0 0 0 53248 1245 454 0 65 35 0 0
0 0 0 1487560 2097680 111484 0 0 1000 0 375 292 0 9 91 0 0
0 0 0 1487744 2097680 111524 0 0 0 0 99 145 0 1 100 0 0
虽然同时写数据,写磁盘跟写文件的现象还是有不同。写磁盘时(也就是bo大于0时),Buffer跟Cache都在增长,但Buffer的增长更快。
这说明,写磁盘用到了大量的 Buffer,这跟在文档中查到的定义是一样的。
案例2:读磁盘数据
echo 3 > /proc/sys/vm/drop_caches
# 运行dd命令读取文件
$ dd if=/dev/sdb4 of=/dev/null bs=1M count=1024```
回到另外一个终端,观察vmstat中的变化:
```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 3642184 24 54120 0 0 0 0 36 54 0 1 100 0 0
0 0 0 3642184 24 54120 0 0 0 0 82 164 0 1 99 0 0
0 0 0 3642184 24 54120 0 0 0 0 65 108 0 0 100 0 0
0 0 0 3642184 24 54120 0 0 0 0 40 51 0 1 100 0 0
1 0 0 2891516 749588 54860 0 0 749564 0 3329 371 0 40 60 0 0
0 0 0 2588152 1052692 55528 0 0 303104 0 1358 65 1 18 82 0 0
0 0 0 2588152 1052692 55528 0 0 0 0 29 43 0 0 100 0 0
0 0 0 2588152 1052692 55528 0 0 0 0 28 40 0 0 100 0 0
1 0 0 2588152 1052692 55528 0 0 0 0 31 45 0 0 100 0 0
2 0 0 2588096 1052692 55528 0 0 0 0 48 59 0 0 100 0 0
0 0 0 2588152 1052692 55528 0 0 0 0 35 45 0 1 99 0 0
0 0 0 2588152 1052692 55528 0 0 0 0 23 36 0 0 100 0 0
0 0 0 2588152 1052692 55528 0 0 0 0 32 43 0 0 100 0 0
观察 vmstat 的输出,会发现读磁盘时(也就是 bi 大于 0 时),Buffer 和 Cache 都在增长,但显然 Buffer 的增长快很多。这说明读磁盘时,数据缓存到了 Buffer 中。
所以可以得到总结:Buffer对磁盘数据的缓存,既会用在读请求中,也会用在写请求中。
ps:
测试完磁盘的读写后,磁盘分区
从
Filesystem Size Used Avail Use% Mounted on
/dev/sdb4 4.8G 20M 4.6G 1% /data
变成了这样
Filesystem Size Used Avail Use% Mounted on
/dev/sdb4 18Z 18Z 0 100% /data
所以记得用空闲的磁盘分区来做测试。