Apache作为老牌的Web服务器,很多站点都会开启mod_cache模块来提升静态资源和反向代理场景的响应速度。但缓存是把双刃剑,用得久了缓存目录动辄几个GB甚至几十GB,磁盘一满整台服务器都会出问题。本文就来聊聊如何写一个安全可用的手动清除缓存脚本,并讲清楚背后的缓存机制,避免清理时踩坑。

一、先搞清楚Apache的缓存存储结构
写脚本之前必须先了解缓存是怎么存的,不然脚本写得再漂亮也可能清错地方。Apache的缓存主要分两种:基于内存的mod_cache_socache和基于磁盘的mod_cache_disk。实际运维中最常见的占用磁盘空间的是后者,它的默认存储路径通常在/var/cache/httpd/mod_cache_disk或者/var/cache/apache2/mod_cache_disk,具体取决于发行版。
mod_cache_disk在存储时会将URL做哈希运算,然后把缓存内容分散到多层子目录中。典型的目录深度配置类似CacheDirDepth 2和CacheDirLength 1,也就是说每个URL对应的缓存文件会散落在两层、每层一个字符的目录里。这种设计的好处是单个目录下文件数量不会爆炸,方便文件系统快速查找,但对清理脚本来说,必须用递归方式处理。
另外要注意,如果你用的是hCache相关方案或者自己配置了CacheRoot指令,缓存路径可能完全自定义。所以在动手写脚本前,先用下面的命令确认实际配置:
grep -r "CacheRoot" /etc/httpd/ /etc/apache2/ 2>/dev/null httpd -M 2>/dev/null | grep cache || apache2ctl -M 2>/dev/null | grep cache
第一条命令找到缓存根目录在哪,第二条确认缓存模块是否启用。这两个信息直接决定脚本里的关键变量怎么填。
二、清理脚本的完整实现
下面是一个生产环境验证过的脚本,核心思路是:先检查缓存目录是否存在且属于Apache进程用户,再按照文件修改时间做条件清理,全程记录日志并统计清理数量。脚本采用参数化设计,支持传入缓存目录和保留天数,方便在不同机器上复用。
#!/bin/bash
# Apache磁盘缓存清理脚本
# 缓存根目录,请根据实际CacheRoot配置修改
CACHE_DIR="/var/cache/httpd/mod_cache_disk"
# 保留最近N天的缓存,只清理更旧的
KEEP_DAYS=7
# 日志文件
LOG_FILE="/var/log/apache_cache_clean.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# 参数检查:缓存目录必须存在
if [ ! -d "$CACHE_DIR" ]; then
log "错误:缓存目录 $CACHE_DIR 不存在,请检查CacheRoot配置"
exit 1
fi
# 获取缓存目录属主,校验是否为apache用户
OWNER=$(stat -c '%U' "$CACHE_DIR")
if [ "$OWNER" != "apache" ] && [ "$OWNER" != "www-data" ]; then
log "警告:目录属主为 $OWNER,与Apache运行用户不符,请人工确认"
read -p "是否继续清理?(y/n) " CONFIRM
[ "$CONFIRM" != "y" ] && exit 1
fi
# 统计清理前占用空间
BEFORE_SIZE=$(du -sh "$CACHE_DIR" | awk '{print $1}')
log "开始清理,当前缓存占用:$BEFORE_SIZE"
# 删除超过保留期的缓存文件
DELETED=$(find "$CACHE_DIR" -type f -mtime +$KEEP_DAYS -print -delete | wc -l)
# 清理空目录,避免哈希目录残留
find "$CACHE_DIR" -mindepth 1 -type d -empty -delete 2>/dev/null
AFTER_SIZE=$(du -sh "$CACHE_DIR" | awk '{print $1}')
log "清理完成,删除文件数:$DELETED,当前缓存占用:$AFTER_SIZE"脚本中有几个细节值得说明。第一,find -mtime +7表示删除修改时间在7天之前的文件,注意这个判断依据是文件的mtime而不是缓存内容的过期时间,两者可能有偏差。如果希望严格按缓存TTL清理,更推荐让Apache自己管理过期,脚本只做兜底清理。
第二,删除文件后紧接着清理空目录是必要的。因为mod_cache_disk的哈希目录只有一层层删空才会消失,否则时间长了会残留大量空目录,虽然不占多少空间,但会让du统计变慢,也会影响后续排查。
第三,脚本里的属主校验是防止误删的保护措施。有些机器上缓存目录可能被改成了root属主,此时如果Apache没有写权限,缓存实际上早就失效了,直接全量删除重启服务即可,没必要走时间过滤逻辑。
三、不同清理策略的选择与注意事项
上面脚本采用的是按时间过滤的温和清理策略,但实际场景中还有另外两种常见做法。第一种是全量清空,即停掉Apache服务后直接删除缓存目录下所有内容,然后重建目录并授权。这种方式最彻底,适合缓存内容已经大面积失效或者磁盘紧急告警的情况。操作命令如下:
systemctl stop httpd rm -rf /var/cache/httpd/mod_cache_disk/* chown -R apache:apache /var/cache/httpd/mod_cache_disk systemctl start httpd
第二种是借助Apache自带的htcacheclean工具。这个工具随Apache一同发布,可以限制缓存总大小并自动清理到指定水位,例如htcacheclean -n -t -p /var/cache/httpd/mod_cache_disk -l 5G表示以后台守护方式把缓存控制在5GB以内。相比自己写脚本,它理解缓存文件的结构,清理时能正确处理数据文件和头文件的配对关系,不会产生半个缓存条目。所以如果是长期运行的服务,优先考虑用htcacheclean做常驻限制,手动脚本只作为应急手段。
无论采用哪种方式,有几点生产环境的注意事项必须牢记。清理缓存后短时间内回源请求会激增,如果后端服务抗压能力弱,建议在业务低峰期操作。执行脚本前务必确认磁盘空间告警不是因为日志文件膨胀导致的,很多时候/var/log下的access_log才是罪魁祸首,别清了半天缓存发现方向错了。最后,可以把脚本配合crontab做每周定时执行,例如0 4 * * 0 /opt/scripts/clean_apache_cache.sh每周日凌晨四点运行,这样就不需要每次都手动操作了。
总结一下,手动清除Apache缓存的脚本并不复杂,关键在于三点:确认真实的缓存路径、选择合适的清理粒度、保留操作日志便于追溯。把这套脚本和htcacheclean结合起来使用,磁盘空间问题基本可以得到稳定控制。
Apache缓存清理mod_cache配置Shell脚本修改时间:2026-09-04 04:16:37