Linux系统缓存过高也会造成接口超时?————Buffer/Cache占用过高问题排查
问题起因
最近一个客户反应有个服务非常卡顿,技术介入排查之后发现经常接口超时,一开始我们怀疑是慢接口之类的问题,对mysql和代码层面进行了排查,发现并没有问题,而且出现问题的接口逻辑也非常简单就是查询了2个不大的表就将数据返回给前端了。
后面问题越来越严重,该服务经常性的出现接口大范围超时,这时候我们将问题的排查放到了服务器本身。
排查CPU和内存使用率问题
- top命令查看内存使用情况
top
从top命令当中我们没有看出明显问题,cpu和内存的占用率一直都在一个合理的范围之内(这个图是我后截的,实际上出问题的时候也没有啥内存飚高的情况发生)。
从一开始,我们就不认为是内存占用问题,然后我们将注意力转移到了网络问题上,联系某云服务器的厂商一起来看了网络问题,最后也发现无异常,这时候我们的排查陷入了困难。
从未关注过的buffer/cache的使用情况
一般我们在查询内存和cpu的占用情况的时候都比较喜欢用top命令,去看占用的内存空间的百分比,一般百分比不过高我们就认为没有问题,但是我也是后面才知道buffer/cache的使用情况也会影响机器性能,进而影响服务的稳定性。
- 使用free查看内存使用情况
free -h
- total是你机器的所有内存空间
- used是已经使用的内存空间,top命令算的内存比例也是按照这个计算的
- free是你机器的剩余内存空间,free = total - used - buff/cache
- shared:共享内存通常用于系统进程间共享数据或者通信。
- buff/cache:缓存用于存储最近访问的数据和文件,以加快对磁盘的访问速度,提升系统性能。
- avaliable:系统预估的可用内存的大小,是空闲内存和缓存的总和,表示系统可以直接使用的空闲资源。
我们系统出现卡顿的时候,free的空间只剩下200MB了,但是available还有16G,一开始我以为available还有16G那么说明系统的内存是够用的,实际上并不是的,接下来我们就介绍下buff/cache是干嘛的。
buff/cache的作用
在 Linux 操作系统中,buff/cache 是内存管理中的一个关键概念。它涉及到操作系统如何使用和管理内存,以提高系统性能和资源利用率。以下是 buff/cache 的具体作用:
-
缓冲区缓存 (Buffer Cache):
- 作用:缓冲区缓存用于存储文件系统元数据(例如,目录信息和 inode 信息)和块设备的临时数据。这些数据在文件系统操作中被频繁访问和修改。
- 优点:通过将这些数据存储在内存中,操作系统可以减少对磁盘的频繁访问,从而提高文件系统操作的速度。
-
页面缓存 (Page Cache):
- 作用:页面缓存用于存储文件数据。当文件被读取时,操作系统会将数据加载到页面缓存中。如果相同的数据再次被访问,操作系统可以直接从内存中读取,而无需再次访问磁盘。
- 优点:通过利用页面缓存,文件读取操作的速度可以大幅提升,因为内存的访问速度远远快于磁盘。
-
释放和回收内存:
- 当系统内存紧张时,Linux 会自动释放
buff/cache中的内容,以腾出内存供其他进程使用。这种机制确保系统能够有效利用内存资源,避免内存不足的情况。 buff/cache中的数据会根据使用频率和优先级进行回收。例如,最近访问的数据会优先保留,而长时间未访问的数据则会被优先回收。
- 当系统内存紧张时,Linux 会自动释放
简单来说buff/cache是为了提升我们Linux系统的磁盘IO速度,或者避免过多的磁盘IO而存在的一个缓存机制,就是将磁盘上的文件,或者一些Page提前缓存到内存里面,当需要使用的时候可以快速获取,增加IO效率。
并且理论上buff/cache所占用的内存当系统内存不足的时候会自动释放,不会影响机器的性能,那么问题来了为什么实际应用中buff/cache影响到了我们服务的正常使用呢?
为什么buff/cache会影响到我们服务的性能?
在实际开发过程中,buff/cache 机制导致 Java 服务卡顿和访问超时的情况可能是由于内存压力导致的内存回收和交换行为。以下是一些可能的原因和解决方法:
内存压力:当系统内存使用率高,特别是当应用程序(如你的 Java 服务)需要大量内存时,Linux 可能会尝试回收 buff/cache 的内容来释放内存。这个过程可能会引起频繁的内存回收和交换(swap),导致系统性能下降。
交换 (Swapping) :如果物理内存不足,Linux 会将一些内存页交换到交换分区(swap space)中。这会导致 I/O 操作,增加系统延迟,影响 Java 服务的响应时间。
内存碎片化: 随着内存使用的增加和减少,内存可能会变得碎片化。这会导致大块的内存分配变得困难,从而引起性能问题。
垃圾回收 (Garbage Collection) :Java 应用程序的垃圾回收机制可能会与操作系统的内存管理产生冲突,特别是在内存紧张的情况下。这会导致长时间的垃圾回收暂停,影响应用性能。
处理方法
- 网上找的定时清理buff/cache脚本
#!/bin/bash
# 需要释放内存的,缓存占用百分比,可以传参,默认是70%
max_cache_rate=$1
if [ ! "$max_cache_rate" ] ; then
max_cache_rate=70
fi
echo "max_cache_rate: $max_cache_rate"
total_mem=$(free -m | awk 'NR==2{print $2}')
cache_mem=$(free -m | awk 'NR==2{print $6}')
cache_rate=$((cache_mem*100/total_mem))
log=/usr/local/logs/mem.log
echo "===========================" >> $log
date >> $log
echo "current_cache_rate: $cache_rate%"
echo "Memory usage | [Total:${total_mem}MB][Cache:${cache_mem}MB]" >> $log
if [ "$cache_rate" -ge "$max_cache_rate" ] ; then
sync && echo 1 > /proc/sys/vm/drop_caches
sync && echo 2 > /proc/sys/vm/drop_caches
sync && echo 3 > /proc/sys/vm/drop_caches
echo "OK, cache memory released" >> $log
else
echo "Not required to release cache memory" >> $log
fi
- linux上执行命令,每30分钟执行一次
crontab -e #打开定时任务编辑器
- 添加30分钟执行一次
*/30 * * * * /usr/bin/sh /home/mem.sh