ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CentOS 7缓存清理实战:从内存到yum、journald的完整方案

CentOS 7缓存清理实战:从内存到yum、journald的完整方案 接了一台跑了好几年的CentOS 7服务器一上来先看内存free -h一敲buff/cache那栏愣是躺了四五个G。旁边的同事眉头一皱“是不是有内存泄漏该清缓存了吧”这种场景我遇到不是一次两次了几乎每天都能在技术群里看到同样的疑问。CentOS 7下清理缓存说难不难说简单也不是一条命令就能搞定的——不同层级、不同用途的缓存处理方式完全不一样盲目执行drop_caches或者删文件轻则白忙一场重则影响业务。这篇就站在实际操作的角度把CentOS 7里几种常见的“缓存”逐个拆开物理内存缓存、yum软件包缓存、journald日志缓存以及临时文件目录配合命令、判断方法和坑点尽量把每一步为什么这么做讲清楚。适合自己折腾服务器的人、刚入行的运维以及被“内存爆满”警告搞得睡不着的开发朋友参考。1. 先搞懂CentOS 7里的缓存到底是什么很多朋友一看到buff/cache占用高第一反应就是“缓存垃圾太多必须清掉”。这个认知其实只对了一半。Linux的缓存机制本身是为了让系统跑得更快而不是故意制造麻烦的。想安全地清理你得先知道它在缓存些什么。1.1 三种内存缓存page cache、dentry cache、inode cacheLinux内核为了减少磁盘I/O会把读过的文件内容、目录结构、文件属性等内容放在内存里下次再访问同样的数据时直接走内存速度能快几个数量级。这里面主要分三类page cache页缓存缓存文件内容本身。你cat过一个日志文件、yum install过软件读过的数据块都会进入page cache。再次读同一个文件时直接从内存返回不用再去磁盘上翻。这类缓存占的空间最大也是最容易被误会的“内存占用大户”。dentry cache目录项缓存缓存的是目录项和文件名的对应关系。比如你ls /etc下次再ls的时候目录结构是从内存里直接拿的不用重新扫描磁盘。inode cacheinode缓存缓存文件元数据包括文件权限、属主、大小、修改时间等。查看文件详情时命中这个缓存就不需要额外做磁盘I/O。这三者合起来就是free -h中buff/cache那一列的主体。正常情况下它们会自动增长、自动回收——当系统内存吃紧时内核会优先释放这些缓存给进程使用。也就是说缓存并不是“不用就浪费了”而是给系统当“预加载缓冲区”用的。1.2 高buff/cache不等于内存不够用判断服务器是不是真的内存不足只看free那一行的数值会得出完全错误的结论。举个例子total used free shared buff/cache available Mem: 7.6G 2.1G 1.2G 112M 4.3G 5.0G Swap: 2.0G 0B 2.0G这张图里free只有1.2G看起来“快爆了”但available显示5.0G。这个available才是系统真正能分配给新进程的内存量因为它已经考虑到了“缓存可以在必要时被回收”。换句话说buff/cache里的4.3G大部分都能在需要时吐出来给应用用。内存有没有压力更应该看available而不是free。也正因如此清理缓存的第一个原则是不要为了“数字好看”去清缓存。只有当你明确看到available持续走低、Swap开始被大量写入、应用的响应明显变慢才需要介入。当然如果缓存占用到了让你心里没底的地步主动清理一次也未尝不可但要用对方法。2. 物理内存缓存怎么清、什么时候清所谓“清内存缓存”核心操作就是Linux内核提供的drop_caches接口。它允许管理员手动丢弃page cache、dentry cache和inode cache。但这家伙跟核弹似的威力大副作用也有用之前务必想清楚。2.1 清理前的现场判断在动手之前先把“该不该清”这个问题用数据确认一遍。我自己的习惯顺序是执行free -h看available是否已经低于总内存的20%到30%同时Swap used是不是在持续上涨。用cat /proc/meminfo看更详细的指标重点看MemAvailable、Dirty和Writeback。Dirty表示脏页数量也就是还没写回磁盘的缓存。如果这个值很大清理前必须执行sync否则可能丢数据。用top -o %MEM或ps aux --sort-%mem确认到底是谁在吃内存排除应用进程本身的内存泄漏。如果应用进程确实占用过多清理缓存治标不治本该排查代码的排查代码该扩容的扩容。如果确认是缓存问题再走下一步。2.2 drop_caches的三种级别与正确姿势/proc/sys/vm/drop_caches可以写三个值分别控制释放的层级写入值释放内容常用场景1释放page cache页缓存读文件导致缓存占用过高且确认不需要这些缓存时2释放dentry cache和inode cache大量创建、删除文件后目录项缓存异常膨胀时3同时释放全部三种缓存系统缓存整体偏高想一次性全部回收时最标准的执行流程是# 先把脏页写回磁盘防止数据丢失 sync # 释放page cache echo 1 /proc/sys/vm/drop_caches # 或者按需释放全部缓存 echo 3 /proc/sys/vm/drop_cachesecho 2单独用的场景不算多我实际工作中更常见的是echo 1和echo 3。另外用sysctl接口更规范一些效果完全一样sync sysctl -w vm.drop_caches1写完这个命令后再执行free -hbuff/cache那一列会肉眼可见地降下来。2.3 生产环境下的稳妥姿势先泼一盆冷水直接往/proc/sys/vm/drop_caches里写3在生产环境是有风险的操作。因为缓存被清空后短期内所有文件读取都会重新走磁盘I/OIO压力会瞬间拉高反而可能拖慢业务。有几次我贪图“清理彻底”用了3结果应用响应在接下来的十几分钟里反而变慢了。后来踏实了只在该用1时用1该用2时用2绝不为了“干净”而过度清理。稳妥的做法是分两种情况处理首次排查只做echo 1 /proc/sys/vm/drop_caches观察available和IO负载的变化不够再升级到3。定期清理不要直接裸跑drop_caches而是把它放进一个带判断条件的脚本里比如内存可用量低于阈值才执行且执行频率限制在每天一次或每周一次。生产环境里还有一个细节在清理之前先用sync把脏页刷回磁盘。脏页就是尚未落盘的内存数据不先同步就丢弃缓存极端情况下会引发文件系统不一致。这一步虽然简单但很多人会漏掉。3. yum与软件包层级的缓存清理磁盘空间不足是另一个常见的“缓存清理”诉求而yum的缓存往往是头号嫌疑。CentOS 7的yum会把下载的软件包、元数据、头文件等都缓存到本地常年不清理的话能堆出好几个G的空间占用。3.1 yum缓存到底占在哪默认情况下yum缓存目录是/var/cache/yum/你还可以通过/etc/yum.conf里的cachedir参数指定。这个目录下按架构、仓库名分了很多子目录里面的packages目录存放的是真正下载下来的rpm安装包metadata里是仓库元数据。装完软件之后这些rpm包并不会自动删除。对于包数量多、更新频繁的服务器来说日积月累很容易攒出几个G的垃圾文件。我在帮客户排查磁盘空间时经常遇到/var/cache/yum/动辄两三个G的情况。先看看空间占用du -sh /var/cache/yum/*然后再决定清理策略。3.2 yum clean命令家族CentOS 7下清理yum缓存的核心命令是yum clean它的几个常用参数各有用处# 清理已下载的软件包文件 yum clean packages # 清理仓库元数据缓存 yum clean headers # 清理全部缓存包文件元数据插件缓存 yum clean all还有一个容易被人忽略的点执行yum clean all之后首次再执行yum install或yum update时yum会因为没有本地元数据缓存而重新下载全部仓库元数据表现为“卡在读取仓库信息”那一步。这是正常现象不是卡死了。如果着急装包可以顺手执行一次yum makecache尽早把元数据缓存建好后面用着流畅。3.3 卸载残留与autoremove除了这些缓存卸载软件时留下的依赖包也是磁盘空间的隐形消耗者。当你yum remove某个软件时曾经跟着它一起装进来的依赖并不会自动卸载它们会变成“孤儿包”继续留在系统里。检查有没有这类残留yum list autoremove如果有输出直接清掉yum autoremove这个操作相当于把不再被任何包依赖的旧依赖全部移除。我一般在每次卸载大软件包后顺手跑一次既能省空间也能减少后续依赖冲突的概率。需要提醒的是执行前最好先看一眼yum list autoremove的输出确认系统核心组件不在列表里再看一次不亏。4. journald日志缓存清理与定时维护方案磁盘空间问题的另一个大头往往在/var/log/journal/也就是systemd的journald日志。CentOS 7默认用systemd接管系统日志journal文件会持续增长。很多人盯着yum缓存看半天却忽略了这里的“日志缓存”可能比yum缓存还要肥。4.1 journal日志是怎么悄悄膨胀的journald会把内核日志、系统服务的标准输出、错误输出等统一写入/var/log/journal/。如果服务的日志打得勤比如某些反复刷报错的组件journal文件增长得非常快。内网的一个测试机曾经因为某个服务疯狂报错半天时间journal目录就吃掉了将近10G磁盘。先看现状# 查看journal日志占用磁盘总量 journalctl --disk-usage4.2 vacuum参数怎么设journald本身支持按体积、按时间、按文件数量清理历史日志最常用的三个参数# 保留最近200M日志更早的自动删除 journalctl --vacuum-size200M # 只保留最近7天的日志 journalctl --vacuum-time7d # 限制最多保留10个journal文件 journalctl --vacuum-files10我更推荐限制体积的方式。因为“时间”和实际日志产生量有关容易失控按体积限制是最直观的比如限制到200M磁盘占用就锁死了。比手动清更有用的是在配置层面限好上限。编辑/etc/systemd/journald.confSystemMaxUse200M SystemMaxFileSize20M其中SystemMaxUse控制整个journal目录的最大总占用SystemMaxFileSize限制单个journal文件大小。修改完重启journaldsystemctl restart systemd-journald这样后续日志不会无限膨胀这比每周手动清一次省心得多。4.3 一次搞定多维度清理整合脚本实际维护中我习惯把多种“缓存清理”动作整合成一个脚本放到crontab里定期执行。这里给一个参考脚本核心思想是“最小必要清理不过度干预”#!/bin/bash # daily_cache_clean.sh - CentOS 7 缓存清理脚本 # 1. 清理yum缓存 /usr/bin/yum clean all /dev/null 21 # 2. 清理老旧的journal日志限制在100M以内 /usr/bin/journalctl --vacuum-size100M /dev/null 21 # 3. 清理/tmp下超过7天未改动的文件 /usr/bin/find /tmp -type f -mtime 7 -delete 2/dev/null # 4. 仅当内存可用量低于总内存15%时才清理page cache total_mem$(awk /MemTotal/{print $2} /proc/meminfo) avail_mem$(awk /MemAvailable/{print $2} /proc/meminfo) threshold$((total_mem / 100 * 15)) if [ $avail_mem -lt $threshold ]; then /bin/sync echo 1 /proc/sys/vm/drop_caches fi把它加到crontabcrontab -e # 每天凌晨3点执行 0 3 * * * /root/daily_cache_clean.sh这里面最值得借鉴的是最后一段逻辑内存清理必须带条件触发而不是无脑每天执行。可用的内存本来就不紧张时频繁清理缓存反而会导致磁盘IO升高得不偿失。5. 常见问题与排查技巧实录清理缓存这件事几乎所有坑我都踩过或者见过别人踩过。这部分列几个高频问题顺便附上我的排查思路。5.1 清理后available没有变多这是最让人困惑的情况执行了echo 3 /proc/sys/vm/drop_cachesfree -h一看buff/cache确实降了但available几乎没涨。原因其实不复杂Linux内核认为“缓存占用的内存可以随时回收”所以在计算available的时候已经把可回收的缓存算进去了。也就是说清理前系统本来就不缺内存现在只是把“预加载的缓存”拆掉了数字自然变化不大。这种情况是正常的不用太在意。真正需要警惕的是另一种available持续处于极低水平同时Swap被大量占用。这时候说明内存确实吃紧单靠清缓存救不了场。优先排查有没有内存泄漏的进程实在不行加Swap或加物理内存才是正解。5.2 drop_caches后系统反而变慢了好多人在清完缓存后发现系统响应变慢、磁盘IO飙升就以为命令执行出错了。其实这也是预期行为缓存本身就是用来减少磁盘读写的你手动把缓存清掉所有之前能命中内存的文件读取行为都要重新走一遍磁盘IO压力自然短期升高。如果业务处于高峰期不建议执行清内存缓存操作。我会优先选择业务低峰期做比如凌晨两三点。实在要在高峰期清至少要配合限流或错峰操作别在同一时间集中触发大流量业务。5.3 yum clean all之后yum install报错报错信息一般长这样Could not retrieve mirrorlist ......这是因为yum clean all把元数据缓存全清了下次执行安装时需要重新拉取仓库信息。如果网络慢可能长时间卡在读取仓库列表那一步。解决办法很简单yum makecache先把元数据缓存重建起来再继续安装操作。日常写脚本时如果脚本里涉及yum clean all我建议紧跟着放一个yum makecache避免脚本在后续步骤里卡死。5.4 清理/tmp导致程序异常清理/tmp目录下的临时文件时最大的坑是有些程序运行期间会把正在用的临时文件放在这里比如Python的tempfile默认目录、某些解压工具的中间文件等。盲目删掉这些正在使用的文件进程可能直接崩溃或者出现诡异报错。所以我清理/tmp时会保守一点只删除超过7天甚至14天没有被修改过的文件而且不会用rm -rf /tmp/*这种粗暴方式。更安全的做法是用find /tmp -type f -mtime 7 -delete甚至可以先find出来看看再删# 先看哪些文件会被删 find /tmp -type f -mtime 7 | head -20 # 确认没问题再删 find /tmp -type f -mtime 7 -delete5.5 磁盘空间还是不够的排查思路如果yum缓存清了、journal日志控制了、/tmp也清理了df -h一看根分区还是红的那就不能只盯着“缓存”了。这时候要按目录逐层定位# 查看哪个一级目录占空间最大 du -h --max-depth1 / | sort -hr | head -10 # 查看/var下哪个子目录占空间最大 du -h --max-depth1 /var | sort -hr | head -10常见的隐藏大户有/var/log/下老旧的日志文件、Docker的镜像与容器层数据/var/lib/docker、数据库文件所在的数据目录、以及Postfix等邮件服务的队列文件。不同业务类型磁盘占用大户完全不同逐层定位是最稳妥的方式。6. 一些个人习惯和经验补充清理缓存这件事技术上本身不复杂真正需要把握的是“分寸”。我自己维护服务器多年总结出三个原则第一尽量用“可控”的方式清理少用“一刀切”的销毁式命令。比如yum clean all之后要记得yum makecacheecho 3 /proc/sys/vm/drop_caches之前要先sync。这些细节看着不起眼关键时刻真的能保数据、保业务。第二能用配置限制上限的就不要靠定期手动清理。journald的SystemMaxUse、yum的keepcache0在/etc/yum.conf里默认为0即装完不保留安装包这个其实大部分机器默认就是关闭的等信息一旦配置到位后续就少了很多麻烦。第三在动手清理之前先回答两个问题清理目标是内存还是磁盘如果磁盘占用到底在哪个目录回答不出来之前不要执行任何删除或drop操作。最后再分享一个小技巧把free -h和df -h的检查写成一行别名最大限度减少排查时的重复操作echo alias chkfree -h echo df -h ~/.bashrc source ~/.bashrc之后登录机器输入chk一眼就能看到内存和磁盘的整体状态判断问题在哪一侧再决定用哪一套清理方案。这个习惯帮我省了不少事也顺便避免了“看到内存缓存高就乱清”的老毛病。
返回列表