记录一次服务器内存使用率过高达到90%告警问题排查。

目录

👩🏽‍💻个人主页:阿木木AEcru

🔥 系列专栏:Docker容器化部署系列

💹每一次技术突破,都是对自我能力的挑战和超越。

一、前言

一大早就有一个电话过来:"你快看看,这台服务器怎么一直在告警,90%的使用率,一直下不去"。

作为牛马的我立马就起身了,心里想:我也不是专业运维啊,啥事都来找我。抱着试一试的心态就上了堡垒机看那下。

二、问题排查处理

首先肯定是先看看目前服务器占用的内存信息

指令描述如下:

free: 这是Linux系统中用于显示内存使用情况的命令。

  1. -s 2: 这个选项指定了更新的时间间隔,单位是秒。在这个例子中,设置为2秒,表示每2秒更新一次内存使用情况。
  2. -c 5: 这个选项指定了输出的次数,即显示内存使用情况的次数。在这个例子中,设置为5,表示输出内存使用情况5次。
  3. -h: 这个选项用于以G为单位显示内存使用情况,以便更容易理解。
    整个指令的作用是每2秒更新一次系统的内存使用情况,并且在终端上显示5次内存使用情况。

输出内容的详细解释如下:

  • total: 总内存量,表示系统中总共的可用内存。
  • used: 已使用的内存量,表示系统当前正在使用的内存。
  • free: 空闲内存量,表示系统中当前未被使用的内存。
  • shared: 多个进程共享的内存量。
  • buffers: 用于缓冲的内存量,通常用于临时存储I/O操作的数据。
  • cached: 用于缓存的内存量,通常用于存储最近使用过的数据,以提高系统性能。
  • available: 可用内存量,表示系统中可供进程使用的内存量,包括空闲内存和缓存。

从这里很容易就看出了可用内存仅剩 1.4G 了,但是已使用内存只用了1.5G。

相信大家也看到了 buffers/cached 占用了 12G 之多,而这个就是罪魁祸首。缓存中的数据大部分都是磁盘文件 数据,是为了提高io。而缓存中的内存是可以被自动释放以及手动释放的。当内存短缺的时候系统会进行自动释放。当然手动释放也是很简单的。通过以下命令即可

sync && echo 3 > /proc/sys/vm/drop_caches

sync 用于将内存中的数据同步到磁盘中,所以在清理最好还是先执行此命令,以防数据丢失。
echo 3 > /proc/sys/vm/drop_caches 是将 3  写入到 该文件中,其作用是作用系统中的缓存。
如果写入数字 1,则会清除页缓存(page cache)。
如果写入数字 2,则会清除目录项缓存(dentry cache)。
如果写入数字 3,则会同时清除页缓存和目录项缓存。

可当我执行完成之后发现, buffers/cached 还是占用了12G ,那说明这里的缓存已经不是通过释放能解决的了。

我就在想, 是什么东西占用了这么多内存,也通过了top命令看了,没有发现什么异常的情况。于是我就想看看是什么占用了这么多内存。 在网上找到,可以在 /proc/meminfo 文件中 查看 当前系统内存使用情况详情。执行后如下

参数解释:

MemTotal: 系统可用的总内存大小,单位为kB(千字节)。

MemFree: 当前未被使用的内存大小,单位为kB。

MemAvailable: 估计当前可用的内存大小,单位为kB。该值是根据当前系统负载和进程执行需要估计出的可用内存大小。

Buffers: 用于存放文件系统的缓存的内存大小,单位为kB。

Cached: 用于存放缓存的内存大小,单位为kB。缓存包括文件系统缓存和页面缓存。

SwapCached: 用于存放交换缓存的内存大小,单位为kB。

Active: 当前活跃的内存大小,单位为kB。活跃内存指正在被使用的内存。

Inactive: 当前不活跃的内存大小,单位为kB。不活跃内存指最近未被访问的内存。

Active(anon): 当前活跃的非匿名内存大小,单位为kB。

Inactive(anon): 当前不活跃的非匿名内存大小,单位为kB。

Active(file): 当前活跃的文件缓存内存大小,单位为kB。

Inactive(file): 当前不活跃的文件缓存内存大小,单位为kB。

Unevictable: 无法被交换出内存的大小,单位为kB。

Mlocked: 已锁定的内存大小,单位为kB。

SwapTotal: 交换空间的总大小,单位为kB。

SwapFree: 交换空间中当前可用的大小,单位为kB。

Dirty: 当前等待被写回磁盘的脏页大小,单位为kB。

Writeback: 当前正在被写回磁盘的页大小,单位为kB。

AnonPages: 匿名页的大小,单位为kB。匿名页指进程私有的内存页,无法被其他进程共享。

Mapped: 已被映射到进程地址空间的页的大小,单位为kB。

Shmem: 共享内存的大小,单位为kB。

Slab: 内核内存管理缓存的大小,单位为kB。

SReclaimable: 可回收的Slab内存大小,单位为kB。

SUnreclaim: 不可回收的Slab内存大小,单位为kB。

KernelStack: 内核栈的大小,单位为kB。

PageTables: 存放页表所占用的内存大小,单位为kB。

NFS_Unstable: 不稳定NFS内存大小,单位为kB。

Bounce: 弹跳缓冲区大小,单位为kB。

WritebackTmp: 临时的待写回页大小,单位为kB。

CommitLimit: 当前系统支持的最大内存使用量,单位为kB。

Committed_AS: 已分配但还未分配物理内存的内存大小,单位为kB。

VmallocTotal: 可用的虚拟内存大小,单位为kB。

VmallocUsed: 已使用的虚拟内存大小,单位为kB。

VmallocChunk: 最大可分配的单个虚拟内存块大小,单位为kB。

HardwareCorrupted: 硬件错误导致的内存损坏大小,单位为kB。

AnonHugePages: 匿名巨页的大小,单位为kB。

CmaTotal: 连续内存区域的总大小,单位为kB。

CmaFree: 当前可用的连续内存区域的大小,单位为kB。

HugePages_Total: 巨页的总数量。

HugePages_Free: 当前可用的巨页数量。

HugePages_Rsvd: 保留的巨页数量。

HugePages_Surp: 超过总数量的巨页数量。

Hugepagesize: 巨页的大小,单位为kB。

DirectMap4k: 直接映射到物理内存的4KB页面的大小,单位为kB。

DirectMap2M: 直接映射到物理内存的2MB页面的大小,单位为kB。

DirectMap1G: 直接映射到物理内存的1GB页面的大小,单位为kB。

从这里就能看出问题了, 在slab 内核内存管理缓存 就占用了大部分, 而且在 SUnreclaim 中就能看出 大部分是不可以被回收的。

导致slab 缓存这么巨大的原因可能有哪些呢?

1、频繁的内存分配和释放 :如果系统中有大量的进程或应用程序频繁地进行内存分配和释放操作,就会导致 Slab 缓存中的内存不断增长。这可能是因为系统在分配内存时无法满足连续的内存需求,导致内核频繁地使用 Slab 分配器进行小块内存的分配。
2、过多的文件系统缓存 :文件系统缓存(Cached)也是由 Slab 缓存来管理的。如果系统中有大量的文件被读取到内存中,并且没有及时释放,就会导致 Cached 缓存占用过多的内存,进而导致 Slab 缓存占用过大。
3、内核模块的使用 :内核模块也会使用 Slab 缓存来管理内存。如果系统中有大量的内核模块被加载,并且这些模块占用了大量的内存,就会导致 Slab 缓存占用过大。
4、内核bug:在一些情况下,可能会存在内核中的 bug 导致 Slab 缓存占用过大。这可能是由于内核中的内存管理机制存在问题,导致 Slab 缓存无法正确地释放内存

到这,我就知道了,因为这台服务器是用做文件存储,应该是比较久之前开发的时候用了 openssh,没有用到专门的对象存储应用,然后留下的坑。频繁的文件操作导致了 slab缓存的累积,只增不减,就出现了这个问题。

然后就去查了怎么看slab 中 的使用情况 。 使用 slabtop 指令就可以查看了。情况如下:

从这里就能看出来被kmalloc占用了大部分,而这个kmalloc又是什么?

在 Linux 内核中,kmalloc 是一种用于动态分配小块内存的函数。它是 Slab 分配器中的一部分,用于分配大小小于等于页面大小的内存块。kmalloc 主要用于内核中的数据结构、缓冲区和其他小型对象的动态分配。

kmalloc 函数的一些特点和用途:

分配小块内存:kmalloc 函数用于分配大小小于等于页面大小(通常为4KB或更大)的内存块。它通常用于分配小型数据结构、缓冲区和其他小型对象所需的内存。

支持高速缓存:kmalloc 分配的内存块可以被 Slab 分配器缓存,以提高分配和释放内存的速度。这意味着相同大小的内存块可能会被缓存起来,以便下次分配时可以更快地完成。

对齐要求:kmalloc 分配的内存块通常会按照一定的对齐要求进行分配。这可以确保分配的内存块在物理内存中的地址是对齐的,以提高访问效率。

实现方式:kmalloc 函数的具体实现会根据系统架构和内核版本而有所不同。在实现上,它可能会调用底层的物理内存分配器,如 Buddy 系统或 Slab 系统,以分配所需大小的内存块。

接下来也找了很久,也没有发现什么好的解决方案,然后目前就是准备重启服务器来解决问题了。如果各位大佬有什么好的解决方案还麻烦在评论区指导一二,感谢!

三、 结尾

感谢您的观看! 如果本文对您有帮助,麻烦用您发财的小手点个三连吧!您的支持就是作者前进的最大动力!再次感谢!

相关推荐
梦游钓鱼1 小时前
在window终端创建docker容器的问题
运维·docker·容器
孤寂大仙v1 小时前
【Linux笔记】理解文件系统(上)
linux·运维·笔记
沉默的八哥2 小时前
K8S高可用Web应用部署方案
运维
winyh52 小时前
Vite 打包后Nginx部署配置
运维·nginx
pyliumy3 小时前
在基于Arm架构的华为鲲鹏服务器上,针对openEuler 20.03 LTS操作系统, 安装Ansible 和MySQL
服务器·架构·ansible
运维小贺3 小时前
Nginx常用的模块
运维·nginx·正则表达式
努力学习的小廉3 小时前
深入了解Linux —— 调试程序
linux·运维·服务器
努力学习的小廉3 小时前
深入了解Linux —— git三板斧
linux·运维·git
只做开心事4 小时前
Linux网络之数据链路层协议
linux·服务器·网络