Latest News : 亮瞎双眼的那些年!

静态文件缓存碰撞解决指南

乱弹 admin 10 views 0 comments

这是一篇关于在多站点环境下,针对 Magento 2 + Varnish + Nginx + Cloudflare
架构中预防和解决“静态文件缓存碰撞(串号)”的技术总结文章。你可以将其作为技术笔记备份。

多站点环境下静态资源缓存冲突(串号)排查与解决方案

1. 现象描述

在同一台服务器上运行多个站点(如 test1.com 和 test2.com),当两个站点的静态资源路径完全一致时(例如
/media/logo.png),用户访问站点 B 却看到了站点 A 的图片。

– 特征 A:清理浏览器缓存无效。
– 特征 B:在 URL 后添加随机参数(如 ?v=1)后,图片显示恢复正常。
– 特征 C:关闭 Cloudflare CDN 后现象消失。

2. 核心原因分析

该问题的根本原因在于缓存键(Cache Key)缺失了“域名(Host)”维度。当多个请求经过缓存层(Cloudflare、Varnish 或 Nginx
Proxy Cache)时,缓存系统仅根据 URL 路径来存储资源,导致不同域名的同名文件在缓存中指向了同一个物理副本。

3. 三层架构的加固方案

第一层:Varnish 缓存键加固(关键)

Varnish 必须显式地将 req.http.host 加入到哈希计算中。如果 VCL 配置中 vcl_hash 只有 URL 路径,就会发生碰撞。

优化后的 vcl_hash 配置:

sub vcl_hash {
# 1. 必须:显式加入 URL 路径
hash_data(req.url);

# 2. 必须:显式加入域名(Host),确保不同站点的同名文件互不干扰
if (req.http.host) {
hash_data(req.http.host);
} else {
hash_data(server.ip);
}

# 3. Magento 2 特有逻辑:区分用户状态(如货币、分组、登录状态)
if ((req.url !~ “/graphql” || !req.http.X-Magento-Cache-Id) && req.http.cookie ~ “X-Magento-Vary=”) {
hash_data(regsub(req.http.cookie, “^.*?X-Magento-Vary=([^;]+);*.*$”, “\1”));
}

# 4. 区分协议:防止 HTTP 和 HTTPS 页面产生混合内容问题
if (req.http.X-Forwarded-Proto) {
hash_data(req.http.X-Forwarded-Proto);
}

# GraphQL 特殊处理
if (req.url ~ “/graphql”) {
call process_graphql_headers;
}

# 注意:此处不建议直接 return(lookup),让其执行默认内置 VCL 以保持兼容性
}

第二层:Nginx 反向代理与缓存配置

即使静态文件绕过了 Varnish,Nginx 自身的代理机制也可能导致问题。

1. 防止 Host 丢失:在所有 proxy_pass 转发块中,必须确保传递原始域名。
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
2. 避免 proxy_cache 碰撞:如果你开启了 Nginx 的 proxy_cache,必须自定义缓存键:
# 默认键通常不含域名,必须手动指定
proxy_cache_key “$host$request_uri”;
3. 多站点 Root 分离:确保 8080(后端端口)针对每个域名有独立的 server 块,防止因匹配到 default_server 而读取了错误的
root 目录。

第三层:Cloudflare 策略优化

当开启 Cloudflare 的“全缓存”(Cache Everything)模式时,边缘节点会极具攻击性地缓存内容。

1. SSL 模式匹配:确保 SSL 模式设置为 Full (Strict)。
– 隐患:若设为 Flexible,CF 会通过 80 端口回源。如果源站 80 端口配置不当(如全部指向一个默认目录),CF
就会抓取错误的内容并缓存。
2. 清理幽灵缓存:
– 一旦发生串号,必须在 CF 后台执行 Purge Everything。
– 串号通常是因为 CF 缓存了源站曾经给出的错误响应(例如源站在配置未完成时返回了 A 站的内容给 B 站)。
3. Cache Keys(高级):
– Cloudflare 默认缓存键包含域名。只要源站响应头正确且 SSL 协议匹配,CF 本身通常不会导致碰撞。

4. 排查与验证工具箱

– 验证 ETag: 使用 curl -I 观察不同域名的响应。如果 ETag 里的文件大小十六进制值完全一样,但磁盘文件大小不同,说明命中了错误的缓存。
curl -H “Host: www.site-a.com” -I https://www.site-a.com/image.jpg
– 对比 MD5: 直接对比源站两个物理文件是否一致:
md5sum /path/to/site-a/image.jpg
md5sum /path/to/site-b/image.jpg
– 绕过 CDN 测试: 修改本地 hosts 将域名直接指向服务器 IP,排除 Cloudflare 层面的干扰。

总结

在 Magento 2 这种多站点架构中,缓存键的唯一性是生命线。

1. Varnish:必须在 vcl_hash 中包含 req.http.host。
2. Nginx:必须在转发时传递正确的 Host 头,并确保 proxy_cache_key 包含 $host。
3. Cloudflare:必须保持 Full SSL 模式回源,并在修复配置后 立即全量清空缓存。

Please indicate: 无趣的人生也产生有意思的事件 » 静态文件缓存碰撞解决指南

Hi, you must log in to comment !