Linux 文件缓存 (一)

缓存印象

缓存给人的感觉就是可以提高程序运行速度,比如在桌面环境中,第一次打开一个大型程序可能需要10秒,但是关闭程序后再次打开可能只需5秒了。这是因为运行程序需要的代码、数据文件在操作系统中得到了缓存,第二次运行程序时可以直接中内存中读取不需要经过磁盘的读取了。除了文件内容外,系统还对文件系统的目录项进行了缓存,这样就不用依次重新从磁盘上查找目录和文件了。从此也可以看出文件/目录缓存是与文件关联的,而不是与某个特定的进程关联的。因为进程结束后,文件缓存依然存在。

缓存查看

Linux中的文件缓存可以通过free命令来进行查看,下面是从一台运行数据库服务的服务器上得到的结果:

[cadmin@bigdb ~]$ free -h
             total       used       free     shared    buffers     cached
Mem:          188G       187G       799M        33G         0B        72G
-/+ buffers/cache:       115G        73G
Swap:          63G       2.8G        60G

-h参数表示使用易于查看的数据单位(默认使用byte)

可以看到第一行的free列中空间只有799MB了,不过不必慌张,cached列中显示占用的空间中72GB用来做了缓存,缓存不是必须存在的,在内存空间紧张时可以减少缓存项。也可以手工进行释放。

丢弃缓存

[cadmin@bigdb ~]$ ls /proc/sys/vm/
admin_reserve_kbytes       hugepages_treat_as_movable  mmap_min_addr             page-cluster
block_dump                 hugetlb_shm_group           nr_hugepages              panic_on_oom
compact_memory             laptop_mode                 nr_hugepages_mempolicy    percpu_pagelist_fraction
dirty_background_bytes     legacy_va_layout            nr_overcommit_hugepages   scan_unevictable_pages
dirty_background_ratio     lowmem_reserve_ratio        nr_pdflush_threads        stat_interval
dirty_bytes                max_map_count               numa_zonelist_order       swappiness
dirty_expire_centisecs     memory_failure_early_kill   oom_dump_tasks            user_reserve_kbytes
dirty_ratio                memory_failure_recovery     oom_kill_allocating_task  vfs_cache_pressure
dirty_writeback_centisecs  min_free_kbytes             overcommit_kbytes         zone_reclaim_mode
drop_caches                min_slab_ratio              overcommit_memory
extfrag_threshold          min_unmapped_ratio          overcommit_ratio

在/proc/sys/vm目录中列出了一些当前虚拟内存系统的状态和参数。我们可以 手工向drop_caches这个文件写入数值进行相应的丢弃缓存操作

1 - 丢弃页缓存(页用来缓存文件内容)

2 - 丢弃文件目录节点缓存(用来缓存元数据,目录结构)

3 - 丢弃上述两者

[root@bigdb cadmin]# sync
[root@bigdb cadmin]# echo "1" > /proc/sys/vm/drop_caches
[root@bigdb cadmin]# free -h
             total       used       free     shared    buffers     cached
Mem:          188G       114G        74G        33G         0B        70M
-/+ buffers/cache:       114G        74G
Swap:          63G       2.8G        60G

可以看到此时cached一项已经从72GB一下子减少到了70MB,不过这样做一般情况下是不应该的。我们需要让系统尽可能的利用可用内存来提供程序运行速度,光有内存可用量并没什么实质的用处。缓存主要还是被页缓存占用,执行第一项后基本也就不会缩小了。执行这个操作不会对以后的缓存策略造成影响,这个操作只是手工触发一次清空(刷出)缓存的操作。

缓存验证

首先生成一个随机文件,大小为1GB

dd if=/dev/urandom of=rnd.dat bs=1MB count=1024

如果刚刚清空了页面缓存此时在用free命令时cached一项应该就在1GB左右

root@controller:~# free -h
             total       used       free     shared    buffers     cached
Mem:           62G        13G        49G       904K        69M       1.0G
-/+ buffers/cache:        12G        50G
Swap:          63G       9.9M        63G

(另外一台服务器上的结果),可见对文件的输出也会生成对应的缓存页。为了以后的测试我们先清空一下缓存。

root@controller:~# free -h
             total       used       free     shared    buffers     cached
Mem:           62G        12G        50G       904K       4.4M        37M
-/+ buffers/cache:        12G        50G
Swap:          63G       9.9M        63G

读取速度

然后我们来测试文件的读入速度,连续两次使用dd命令

root@controller:~# dd if=rnd.dat of=/dev/null bs=1MB
1024+0 records in
1024+0 records out
1024000000 bytes (1.0 GB) copied, 2.58692 s, 396 MB/s
root@controller:~# free -h
             total       used       free     shared    buffers     cached
Mem:           62G        13G        49G       904K       1.3M       1.0G
-/+ buffers/cache:        12G        50G
Swap:          63G       9.9M        63G
root@controller:~# dd if=rnd.dat of=/dev/null bs=1MB
1024+0 records in
1024+0 records out
1024000000 bytes (1.0 GB) copied, 0.393087 s, 2.6 GB/s

root@controller:~# dd if=rnd.dat of=/dev/null bs=1MB
1024+0 records in
1024+0 records out
1024000000 bytes (1.0 GB) copied, 0.323672 s, 3.2 GB/s

可以看到第一次在无系统缓存的情况下读取是将近400MB/s,而第二次在有了缓存的情况下是2.6GB/s,最后一次则达到了3.2GB/s(这里使用的分区是RAID1上的,RAID卡自带缓存)。读取上的速度提升非常明显。

写入速度

首先先复制一份1GB的数据文件以备后用。使用/dev/zero作为输入来源,使用dd命令进行写入测试(不丢弃原来的缓存)

root@controller:~# dd if=/dev/zero of=rnd.dat bs=1024MB count=1
1+0 records in
1+0 records out
1024000000 bytes (1.0 GB) copied, 3.91219 s, 262 MB/s

root@controller:~# dd if=/dev/zero of=rnd.dat bs=1024MB count=1 oflag=direct
1+0 records in
1+0 records out
1024000000 bytes (1.0 GB) copied, 2.66657 s, 384 MB/s

direct即不使用缓存直接进行写入操作,direct模式居然比使用缓存的还要快,这非常不合理。如果使用strace跟踪第一条命令的话,会发现很多时间其实用在了close调用上。

root@controller:~# strace -tt dd if=/dev/zero of=rnd.dat bs=1024MB count=1
20:24:00.207073 execve("/bin/dd", ["dd", "if=/dev/zero", "of=rnd.dat", "bs=1024MB", "count=1"], [/* 23 vars */]) = 0
20:24:00.207857 brk(0)                  = 0x84c000
.......
20:24:00.212135 open("/dev/zero", O_RDONLY) = 3
20:24:00.212246 dup2(3, 0)              = 0
20:24:00.212342 close(3)                = 0
20:24:00.212432 lseek(0, 0, SEEK_CUR)   = 0
20:24:00.212528 open("rnd.dat", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
20:24:00.625270 dup2(3, 1)              = 1
20:24:00.625401 close(3)                = 0
20:24:00.625502 mmap(NULL, 1024012288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1cd975c000
20:24:00.625646 read(0, ""..., 1024000000) = 1024000000
20:24:01.183562 write(1, ""..., 1024000000) = 1024000000
20:24:02.454654 close(0)                = 0
20:24:02.454884 close(1)                = 0
20:24:04.815079 open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 0
20:24:04.815331 fstat(0, {st_mode=S_IFREG|0644, st_size=2570, ...}) = 0
20:24:04.815444 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1d16dd3000
20:24:04.815553 read(0, "# Locale name alias data base.
#"..., 4096) = 2570
20:24:04.815704 read(0, "", 4096)       = 0
20:24:04.815796 close(0)                = 0
20:24:04.815885 munmap(0x7f1d16dd3000, 4096) = 0
20:24:04.816016 open("/usr/share/locale/en_HK/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
20:24:04.816120 open("/usr/share/locale/en/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
20:24:04.816215 open("/usr/share/locale-langpack/en_HK/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
20:24:04.816307 open("/usr/share/locale-langpack/en/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
20:24:04.816442 write(2, "1+0 records in
1+0 records out
", 311+0 records in
1+0 records out
) = 31
20:24:04.816594 write(2, "1024000000 bytes (1.0 GB) copied", 321024000000 bytes (1.0 GB) copied) = 32
20:24:04.816747 write(2, ", 4.1912 s, 244 MB/s
", 21, 4.1912 s, 244 MB/s
) = 21
20:24:04.816869 close(2)                = 0
20:24:04.816959 exit_group(0)           = ?
20:24:04.822877 +++ exited with 0 +++

close(1)用了比write还多的时间,有理由相信,在close调用上面进行了相关的文件同步写入工作。

原文地址:https://www.cnblogs.com/lailailai/p/4497352.html