apache mod_cache + mod_socache_dbm 必须配锁,否则高并发下缓存击穿必然发生;需启用cachelock on、指定cachelockpath、设置cachelockmaxage并加载socache_dbm模块,否则锁逻辑静默失效。

Apache mod_cache + mod_socache_dbm 为什么必须配锁
缓存击穿在高并发下不是“可能”,而是“必然”——当某个热门 CacheKey 过期瞬间,大量请求穿透到后端,压垮源站。Apache 自带的 mod_cache 默认不加锁,多个子进程/线程会同时重建同一缓存项,造成 N 倍回源。真正起作用的是 mod_socache_dbm(或 mod_socache_memcache)配合 CacheLock on 实现分布式缓存锁。
启用 CacheLock 的最小必要配置
只开 CacheLock on 不生效,必须搭配共享对象缓存(socache)和锁超时控制。否则 Apache 会静默忽略锁逻辑,你以为防住了,其实没锁。
-
LoadModule socache_dbm_module modules/mod_socache_dbm.so和LoadModule cache_module modules/mod_cache.so必须显式加载(部分发行版默认不启mod_socache_dbm) -
CacheLockPath /var/cache/apache2/cache-lock路径需存在且 Apache 进程可写(SELinux 下常因上下文拒绝写入) -
CacheLockMaxAge 5是关键:锁最长持有 5 秒,超时自动释放,避免单个慢请求长期霸占锁 -
CacheIgnoreHeaders Set-Cookie建议加上,否则带Set-Cookie的响应默认不缓存,锁也白加
CacheLock 在反向代理场景下的典型失效点
你配好了锁,但监控仍看到大量回源?大概率是 CacheKey 不一致导致锁根本没对上。反向代理中常见三类错位:
- 客户端带
Cookie或Authorization头,而CacheIgnoreHeaders没覆盖,导致每个用户生成独立缓存项和独立锁 - URL 中含动态参数如
?t=123456789,但没用CacheIgnoreQueryString off或CacheIgnoreURLSessionIdentifiers清洗,锁分散在无数变体上 - 后端返回
Vary: User-Agent,但移动端/桌面端共用同一缓存路径,锁被不同 UA 请求各自抢占,互不感知
验证锁是否真实生效的实操方法
别信配置文件,要看日志和行为。Apache 不输出“锁已获取”这种提示,得靠间接证据:
- 开启
CacheLock on后,用ab -n 100 -c 50 http://your-site/压测热点 URL,观察后端 access log 的请求数——应明显少于 50(比如稳定在 1–3 次),说明锁阻塞了其余请求 - 检查 Apache error log 是否有
cache lock acquired或cache lock timeout(需 LogLevel debug);没有不代表没锁,但有就确认锁链跑通了 - 临时把
CacheLockMaxAge设为 1,再压测:若后端请求数激增,说明锁确实在起作用,只是超时太短导致频繁失效
锁机制本身不解决缓存雪崩或穿透的根源,它只买时间窗口——足够让第一个请求建好缓存,其余请求等结果。真正的防御还得靠预热、降级、布隆过滤器这些,Apache 的锁只是最薄但最必要的那层纸。










