1.问题现象
1.htop free命令发现系统 buffer/cache 内存占用高
free -h
total used free shared buff/cache available
Mem: 61Gi 15Gi 569Mi 1.7Gi 45Gi 43Gi
Swap: 30Gi 0.0Ki 30Gi
cat /proc/meminfo
orgrep -E "Buff|Cache" /proc/meminfo
Buffers: 370568 kB
Cached: 45599784 kB
SwapCached: 0 kB
2.问题原因
原理
- cache 读数据保存到内存,加速下次读速度
- buffer 写缓冲区
linux 系统为了提高下一次读取速度, 从内存cache中读取
cache加速读实例
第一次读取
dd if=/dev/zeroo of=test.img bs=1M count=512
free -h
# 查看内存total used free shared buff/cache available
Mem: 15Gi 3.7Gi 10Gi 516Mi 993Mi 11Gi
Swap: 4.0Gi 0B 4.0Gi
time grep 123 test.img
real 0m0.480suser 0m0.138s
sys 0m0.110s
第二次读取
free -h
# 查看内存, 确认cache是否增加total used free shared buff/cache available
Mem: 15Gi 3.7Gi 10Gi 516Mi 1.5Gi 11Gi
Swap: 4.0Gi 0B 4.0Gi
time grep 123 test.img
real 0m0.163suser 0m0.102s
sys 0m0.061s
结论:
- buffer/cache 由 993Mi 变为1.5Gi
- 第二次读取, 匹配关键字速度提升 0.480s --> 0.163s
3.优化与解决方法
1.不解决: 当系统内存不足时, 主动释放cache, 提供给程序,系统需要的内存
2.需要优化的场景
- 确认文件只需要读取一次, 后续不会再次读取: 比如配置文件, 只读取一次的数据
1.测试示例: posix_fadvise主动释放读缓存cache
在线gitee代码: 4_read_cache_读缓存优化_posix_fadvise.c
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define KB_SIZE 1024
#define MB_SIZE (1024 * KB_SIZE)
#define GB_SIZE (1024 * MB_SIZE)
#define BUF_4K (4 * KB_SIZE)
void show_cache_buffer_info()
{
system("free -m");
system("grep -E 'Buffers|Cached' /proc/meminfo");
}
void help()
{
char *help_str = "\
默认 正常读文件 \n\
1 n NOREUSE \n\
2 d DONTNEED\n";
printf("%s", help_str);
}
int main(int argc, char *argv[])
{
int ret = 0;
// 1.生产大文件
if((ret=access("testfile.img", F_OK)) != 0)
system("dd if=/dev/zero of=testfile.img bs=1M count=512");
// 2.清空系统缓存
system("sync; echo 3 > /proc/sys/vm/drop_caches");
show_cache_buffer_info();
// 3.打开文件
int fd = open("testfile.img", O_RDONLY);
if (fd < 0)
{
perror("open");
exit(1);
}
// // 4.读缓存优化 --> 释放缓存,要在读取完之后再释放
// if (argc == 2)
// {
// char opt = *argv[1];
// if (opt == '1')
// posix_fadvise(fd, 0, 0, POSIX_FADV_NOREUSE);
// if (opt == '2')
// posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
// }
// 5.读文件
char buf[BUF_4K];
while (1)
{
ret = read(fd, buf, BUF_4K);
if (ret < 0)
{
perror("read");
exit(1);
}
if (ret == 0)
{
break;
}
}
// 6.释放读缓存
fsync(fd); // fsync将写数据落盘,这样才能确保 page cache全部释放成功
if (argc == 2)
{
char opt = *argv[1];
if (opt == '1' || opt == 'n')
posix_fadvise(fd, 0, 0, POSIX_FADV_NOREUSE);
if (opt == '2' || opt == 'd')
posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
}
close(fd);
show_cache_buffer_info();
}
1.默认读取文件--测试数据
time ./4_read_cache_读缓存 优化_posix_fadvise.out
total used free shared buff/cache available
Mem: 15998 3566 11440 516 991 11636
Swap: 4096 0 4096
Buffers: 2828 kB
Cached: 938928 kB
SwapCached: 0 kB
total used free shared buff/cache available
Mem: 15998 3555 10936 516 1506 11647
Swap: 4096 0 4096
Buffers: 3544 kB
Cached: 1464996 kB
SwapCached: 0 kB
real 0m0.491s
user 0m0.032s
sys 0m0.165s
2.posix_fadvise POSIX_FADV_NOREUSE预期对文件中的信息的访问不会重复 -- 测试数据
time ./4_read_cache_读缓存 优化_posix_fadvise.out 1
total used free shared buff/cache available
Mem: 15998 3554 11452 516 990 11648
Swap: 4096 0 4096
Buffers: 2428 kB
Cached: 938988 kB
SwapCached: 0 kB
total used free shared buff/cache available
Mem: 15998 3549 10942 516 1505 11653
Swap: 4096 0 4096
Buffers: 3300 kB
Cached: 1465136 kB
SwapCached: 0 kB
real 0m0.513s
user 0m0.026s
sys 0m0.218s
3.posix_fadvise POSIX_FADV_DONTNEED丢弃任何与该区域相关的缓存 -- 测试数据
time ./4_read_cache_读缓存 优化_posix_fadvise.out 2
total used free shared buff/cache available
Mem: 15998 3562 11444 516 991 11640
Swap: 4096 0 4096
Buffers: 3028 kB
Cached: 938740 kB
SwapCached: 0 kB
total used free shared buff/cache available
Mem: 15998 3560 11442 516 994 11642
Swap: 4096 0 4096
Buffers: 4012 kB
Cached: 941124 kB
SwapCached: 0 kB
real 0m0.538s
user 0m0.035s
sys 0m0.232s
4.测试小结:
通过系统API posix_fadvise POSIX_FADV_DONTNEED 可以主动释放文件读缓存cache
4.总结
- 读缓存cache, 是系统为了提高下一次读取速度, 保存文件内存在内存中
- 确认是否优化减少读缓存cache
- 目前已知的读缓存cache优化点
- 文件只需要读取一次, 后续不会再次读取: 如配置文件, 或只读取一次的数据