在Apache的mod_cache体系里,TTL并不是一个写死在某一行的参数,而是由源站响应头、mod_cache指令和缓存存储模块共同计算出来的结果。理解这条计算链路,才能真正控制反向代理缓存什么时候失效、什么时候继续复用旧响应。

先拆解Apache缓存TTL的计算顺序
Apache启用磁盘缓存后,常见的配置会把CacheRoot、CacheEnable和几个过期相关指令放在一起。TTL的优先级大致可以这样理解:如果源站返回了Cache-Control: max-age或Expires头,Apache会优先尊重源站的过期时间,但这个时间还会受到CacheMinExpire和CacheMaxExpire的夹逼限制。比如源站给的max-age只有20秒,而本地设置了CacheMinExpire 300,那么最终缓存至少会保留300秒;反过来,源站给了一天过期时间,但CacheMaxExpire 7200会把它压缩到2小时。
如果源站既没有显式过期头,也没有Last-Modified,CacheDefaultExpire就会作为默认TTL兜底。很多动态接口会返回Cache-Control: no-cache,这类响应默认不会被缓存,除非你通过CacheIgnoreCacheControl强制处理,但这通常不是一个好主意。另一个容易忽略的参数是CacheLastModifiedFactor,它根据资源的最后修改时间与当前时间的差值乘以一个系数来推导过期时间,适合那些没有明确TTL但会规律更新的静态文件。
下面是基础配置示例:
CacheRoot /var/cache/apache2/mod_cache_disk CacheEnable disk / CacheDefaultExpire 1800 CacheMinExpire 300 CacheMaxExpire 7200 CacheIgnoreNoLastMod On CacheLastModifiedFactor 0.1
这段配置表示所有URL都启用磁盘缓存,TTL默认1800秒,最小不低于300秒,最大不超过7200秒。需要注意的是,CacheIgnoreNoLastMod On的作用是允许没有Last-Modified头的响应也能被缓存,但这会让一些从不更新的接口长期占用磁盘,最好只在确认响应内容可缓存时开启。
htcacheclean负责磁盘淘汰,但它不会自动运行
mod_cache_disk本身只负责写入缓存文件,不会在磁盘快满时主动清理旧文件。真正执行淘汰动作的是Apache自带的htcacheclean工具。这个工具支持两种运行模式:单次清理模式和守护进程模式。单次清理可以用-t参数手动执行,适合配合cron任务定期调用;守护进程模式用-d启动,设置一个检测间隔,由后台进程持续控制缓存目录大小。
下面是一条常见的守护进程启动命令:
htcacheclean -d -p /var/cache/apache2/mod_cache_disk -l 2048M -i 30
其中-p指向缓存根目录,-l是允许的最大磁盘占用,-i是检查间隔秒数。Apache 2.4在多数发行版中会通过apache2.service或初始化脚本自动拉起htcacheclean,但如果缓存目录是自定义路径,这项服务经常被遗漏,结果就是缓存无限增长。建议配置完成后先手动跑一次单次清理:
htcacheclean -t -p /var/cache/apache2/mod_cache_disk -l 2048M
htcacheclean在扫描时会根据文件的时间戳信息挑选最旧的缓存文件进行删除,优先降低磁盘占用。这里并没有精确的LRU链表,所以它更接近基于时间的批量淘汰,而不是严格意义上的访问频率淘汰。为了让扫描效率更高,缓存目录层级由CacheDirLevels和CacheDirLength控制。例如CacheDirLevels 3配合CacheDirLength 2会生成三层目录,每层使用2个十六进制字符命名。层数越深,单目录文件数量越少,清理和查找速度更快,但路径解析成本也会略微增加。
有一个常见误区是以为设了CacheMaxExpire就能限制磁盘总量。其实CacheMaxExpire只控制单个缓存对象的最长存活时间,不能阻止高频访问产生大量不同URL的缓存文件。磁盘使用上限必须依赖htcacheclean的-l参数或cron清理脚本来实现。
一个可落地的调优配置与验证方法
要同时兼顾命中率和磁盘安全,可以把TTL设置和淘汰策略组合起来。下面这份配置适合静态资源较多的反向代理场景,源站更新不频繁时能显著减少回源请求:
<IfModule mod_cache.c>
<IfModule mod_cache_disk.c>
CacheRoot /var/cache/apache2/mod_cache_disk
CacheEnable disk /
CacheDirLevels 3
CacheDirLength 2
CacheDefaultExpire 3600
CacheMinExpire 600
CacheMaxExpire 21600
CacheIgnoreNoLastMod Off
CacheLastModifiedFactor 0.2
CacheIgnoreCacheControl Off
CacheLock on
CacheLockMaxAge 5
</IfModule>
</IfModule>
这里把CacheMaxExpire设为21600秒,也就是6小时,即使源站返回更长的max-age,本地也最多保留6小时,避免旧版本文件迟迟不更新。同时CacheMinExpire设为600秒,哪怕源站只给60秒TTL,也能在10分钟内继续用本地缓存,这对于一些CDN回源延迟较高的场景很有价值。开启CacheLock可以缓解缓存击穿,当一个热门资源过期后,只允许一个请求回源重建缓存,其他请求等待或继续使用旧缓存。
配置完成后先用apachectl configtest检查语法,再优雅重启服务。然后可以通过curl -I观察响应头:
curl -I http://ipipp.com/static/app.js
第一次请求通常返回X-Cache: MISS,随后重复请求应该变成X-Cache: HIT,Age字段会显示该对象已经在本地缓存中存活的秒数。如果发现Age持续增长到CacheMaxExpire附近,说明TTL边界符合预期;如果始终没有HIT,大概率是源站响应头中包含Cache-Control: no-store或Set-Cookie,需要根据实际业务决定是否调整缓存策略。
最后还要检查htcacheclean是否真的在运行。ps -ef | grep htcacheclean或systemctl status htcacheclean都可以查看。如果已经运行,可以再用du -sh /var/cache/apache2/mod_cache_disk观察目录大小是否稳定在-l限制附近。这样才能确认TTL和淘汰策略两个环节都生效,而不是只做完配置就结束。
Apache代理缓存TTL缓存淘汰策略修改时间:2026-10-06 19:48:23