目录
一、项目简介
之前做了一个语音系统,断断续续稳定运行了四年多。前两天突然报故障,系统每10分钟会重启一次。
这个语音系统当时做的比较复杂:冷机主备,双license,带文件同步、数据同步,同时有大量的系统分析文件生成。
二、问题分析
查看系统后,发现free只有700M,但是buff/cache却有7G+。由于系统已经运行四年以上,语音及管理系统代码泄露内存问题已经基本解决完了。而且如果是我们主要进程代码内存泄露一般也不会泄漏到buff/cache。
由于系统有文件同步和数据同步功能,再结合buff/cache的功能,考虑是数据同步或者文件同步引起的buff/cache增长。
怎么得出的结论呢:
- 双(主备)系统重启,10分钟内buff/cache会把10G左右内存吃完
- 只启动主机,buff/cache基本不会增长到离谱的地步,并能稳定运行。
到这儿基本就分析的差不多了。系统重启的原因是:未知原因的文件或者数据同步导致buff/cache把内存吃完,主要程序申请不到资源异常退出。系统监控到主要程序退出,重新拉起失败后重启设备,让系统转为备机运行。备机上重复此步骤,导致整系统重启。
三、问题处理
原因已经找到,那处理的方法也就有了:
1,找到数据同步/文件同步消耗大量buff/cache的根因。
2,让系统不要进行数据同步/文件同步。
3,找到方法使buff/cache能快速回收,从而不影响系统正常运行。
由于是现场环境所以先采用3稳住局势,然后考虑1,2的操作时间和风险。
什么是buffer/cache?
buffer/cache 其实是作为服务器系统的文件数据缓存使用的,尤其是针对进程对文件存在 read/write 操作的时候,所以当你的服务进程在对文件进行读写的时候,Linux内核为了提高服务的读写速度,则将会把文件放在此处的 buffer/cache 中进行缓存使用,由于 Linux服务的特点便是任何事物都会以文件的形式进行存在,所以你会发现不管你是否对文件做了大规模的读写,机器的 buffer/cache 是一直都存在的,并且持续的增高不下,这是因为服务器所产生的网络连接也好,用户协议的(UDP)套接字也好,这部分的数据系统都会为应用程序创建对应的文件描述符,而这些文件描述符的使用,则又都会重新进入 buffer/cache 中做读写使用,所以这也是你的机器始终都会存在较高 buffer/cache 的原因!
Free中的buffer和cache:(它们都是占用内存):
buffer : 作为buffer cache的内存,是块设备的读写缓冲区
cache: 作为page cache的内存, 文件系统的cache
如果 cache 的值很大,说明cache住的文件数很多。如果频繁访问到的文件都能被cache住,那么磁盘的读IO bi会非常小
buffer/cache 需要注意的一些特点
在服务内存够用的情况下,Linux内核为了加快对文件的读写效率会将文件放入之 buffer/cache 中 以保证读写效率,但其实,尽管当你的应用程序对文件的读写运行结束后,buffer/cache 也不会自动释放该部分内存,而是作为缓冲进行保留,等到你的服务进程在下一次进行相同文件的读写时就可以直接使用,省去了各种重新进行内存初始化的操作;所以这将会导致,当你的应用进程频繁对不同的文件进行读写时,你会发现服务所可以直接使用的free内存将会越来越少的一个重要原因;难道 buffer/cache 在这样无休止的缓存当中就不会自动释放?当然不是,当服务器在内存压力较大的情况下时,则将会自动进行内存的回收,作为free空间分给其它进程使用,这其中主要回收的一个内存则是 buffer/cache 的缓冲区内存块;
如何进行手动 buffer/cache 回收
除了在系统进程内存使用较大压力的情况下进行内存的回收外,我们也可以进行手动的buffer/cache回收,但由于buffer/cache主要是用于文件的读写使用,所以进行文件回收时,一般常伴随系统的IO彪高,因为系统内核也对比cache中的数据与硬盘中的数据是否一致,如果不一致需要写入,然后才能进行内存的回收;
三种方式:
1,echo
清理pagecache(页面缓存)
sync;
echo 1 > /proc/sys/vm/drop_caches
清理dentries(目录缓存)和inodes
sync;
echo 2 > /proc/sys/vm/drop_caches
清理pagecache、dentries和inodes
sync;
echo 3 > /proc/sys/vm/drop_caches
2,sysctl ,有的系统/proc/sys/vm/drop_caches是不可读写的只能用sysctl
清理pagecache(页面缓存)
sync;
sysctl -w vm.drop_caches=1
清理dentries(目录缓存)和inodes
sync;
sysctl -w vm.drop_caches=2
清理pagecache、dentries和inodes
sync;
sysctl -w vm.drop_caches=3
3,还是 sysctl,但是是永久保存的
在/etc/sysctl.conf文件中配置:vm.drop_caches=1/2/3,然后sysctl -p生效
手动 buffer/cache 回收可能出现的问题
但是单纯的手动清除buff/cache是可行的?显然不完全可行。开始我也是这么想的,反正是buff/cache占内存,那么定时清理就行,于是写了如下脚本,可能是没有sync还是别的原因这个脚本运行了一天多就发现系统会时不时自动重启。经过分析,应该可能是清除了正在使用的文件描述符导致的功能性故障。
#!/bin/bash
for (( ; ; ))
do
sysctl -w vm.drop_caches=3
sleep 120
done
如何让系统自动回收buffer/cache
Liunx提供了一些内核参数来管理虚拟内存子系统,这些参数可以用来配置系统的虚拟内存管理策略,包括内存分配、页面置换、内存压缩、NUMA 等方面的设置。用户和系统管理员可以通过修改这些内核参数来调整系统的内存管理行为,以优化系统性能或满足特定的应用需求。
# ls /proc/sys/vm/ -al
admin_reserve_kbytes
block_dump
compact_memory
compact_unevictable_allowed
dirty_background_bytes
dirty_background_ratio
dirty_bytes
dirty_expire_centisecs
dirty_ratio
dirty_writeback_centisecs
dirtytime_expire_seconds
drop_caches #写入这个文件可以释放页缓存、目录项缓存和inode缓存。
#写入1释放页缓存,写入2释放目录项和inode缓存,写入3释放所有缓存
extfrag_threshold
highmem_is_dirtyable
laptop_mode
legacy_va_layout
lowmem_reserve_ratio
max_map_count
min_free_kbytes #设置系统保留的最小空闲内存量。当空闲内存低于这个值时,内核会尽力释放内存
mmap_min_addr
mmap_rnd_bits
oom_dump_tasks
oom_kill_allocating_task
overcommit_kbytes
overcommit_memory
overcommit_ratio
page-cluster
panic_on_oom
percpu_pagelist_fraction
stat_interval
stat_refresh
swappiness
user_reserve_kbytes
vfs_cache_pressure #调整内核回收用于目录项和inode对象缓存的倾向。
#值越高,内核回收这些缓存的频率越高
watermark_boost_factor
watermark_scale_factor
这次处理问题我只关注写有注释的三个参数:
- drop_caches
手动清除buffer/cache时用的
- min_free_kbytes
设置系统保留的最小空闲内存量。当空闲内存低于这个值时,内核会尽力释放内
- vfs_cache_pressure
调整内核回收用于目录项和inode对象缓存的倾向。值越高,内核回收这些缓存的频率越高
vfs_cache_pressure这个值经过分析,如果调大会导致cpu和io中断增加所以本次问题处理未使用。所以这次问题处理只使用了min_free_kbytes这个参数。
vm.min_free_kbytes
min_free_kbytes参数是Linux内核中的一个重要参数,它指定了在系统内存使用达到一定闻值时,必须保留的最小空闲内存量。当系统内存使用量达到vm.min_free_ktes指定的值时,Linux内核将不得不过回收缓存和页面等方式来释放内存,以确保系统的稳定性和可靠性。
通常情况下,vm.min_free_kbytes的默认值已经足够满足大多数系统的需求,但是在某些情况下,比如进行大量内存操作的系统,可能需要适当调整vm.min free kbytes的值,以避免内存不足导致系统崩溃或性能下降。
需要注意的是,vm.min_free_kbytes的设置需要根据具体的系统环境和应用场景来确定,如果设置不当可能会带来负面影响。比如你系统内存只有4G,你设置40G,会导致系统原地死机,必须手动重启(不要问我时怎么知道的)
设置方法同drop_caches
1,echo
echo "2048000" > /proc/sys/vm/min_free_kbytes
2,sysctl
sysctl -w vm.min_free_kbytes=2048000
2,sysctl 永久保存
在/etc/sysctl.conf文件中配置:vm.min_free_kbytes=2048000,然后sysctl -p生效
四、参考文献
Linux:/proc/sys/vm/目录各文件详解-CSDN博客