自建 Varnish 反向代理缓存配置指南

自建 Varnish 反向代理缓存配置指南

如果你的站点对 CDN 成本敏感、又希望在自有服务器上拥有可控的边缘缓存层,那么自建 Varnish 反向代理缓存 是性价比极高的方案。Varnish 是一款专为 HTTP 设计的高性能反向代理缓存,单机轻松处理每秒数万请求,内存命中后的响应延迟可低至 1 毫秒。本文将教你如何从零完成 Varnish 部署,覆盖 VCL 语法、TLS 终结、Backend 健康检查、PURGE 接口与监控告警,帮你解决”装上 Varnish 却没看到命中率提升”这类常见问题。

一、Varnish 适合什么场景

Varnish 与 CDN 不是替代关系,而是互补:CDN 把内容缓存到全球节点,Varnish 把内容缓存到离应用服务器最近的同机房节点,能进一步压低 P99 延迟、削平应用层突发负载。判断你的业务是否值得引入 Varnish,可以参考三点:

  • 内容更新频率低于秒级:例如商品详情、文章页、API 响应。
  • 应用服务器 CPU 已成瓶颈:每秒请求数高、PHP/Python 渲染昂贵。
  • 希望减少回源费用:自建 Varnish 可拦截 70% 以上的 CDN 回源请求。

如果你的应用服务器布在跨境链路上,Varnish 应该部署在应用同机房而非反向。机房与线路的选择可以参考 WordPress 香港主机选购指南云服务器选购指南 中关于内网延迟与出口带宽的章节。

二、安装与基础配置

以 Ubuntu 22.04 为例,通过 packagecloud 提供的官方仓库脚本安装最新的 Varnish 7.5 LTS:先 curl 拉取并执行仓库注册脚本,再 sudo apt install varnish 即可。

Varnish 默认监听 6081 端口,回源端口 6082。生产环境通常前面挂 Nginx 做 TLS 终结,把 80 与 443 接入 Nginx,Nginx 再 proxy_pass 到 Varnish 的 6081。这种分层结构让证书续签、HTTP/2 启用、限流等逻辑都集中在 Nginx 层,Varnish 专注做缓存。修改 /etc/varnish/default.vcl

vcl 4.1;

backend default {
  .host = "127.0.0.1";
  .port = "8080";
  .probe = {
    .url = "/healthz";
    .timeout = 1s;
    .interval = 5s;
    .window = 3;
    .threshold = 2;
  }
}

sub vcl_recv {
  if (req.method == "PURGE") {
    if (!client.ip ~ purge_acl) {
      return (synth(405, "Not allowed."));
    }
    return (purge);
  }

  if (req.url ~ "^/wp-admin/" || req.url ~ "^/wp-login\.php") {
    return (pass);
  }

  unset req.http.Cookie;
}

acl purge_acl {
  "127.0.0.1";
  "10.0.0.0"/8;
}

修改 /etc/varnish/varnish.params 设置缓存大小:

DAEMON_OPTS="-a :6081 -T 127.0.0.1:6082 -s malloc,2G -f /etc/varnish/default.vcl"

-s malloc,2G 表示用 2 GB 内存做缓存,按物理内存的 30% 到 50% 调整。改完后 sudo systemctl restart varnish 让新的配置生效。

三、TLS 终结:用 Hitch 或 Nginx

Varnish 本身不处理 TLS,社区方案两种:Hitch(官方推荐的轻量 TLS 终结代理,通过 PROXY protocol 与 Varnish 通信)或 Nginx(通用反向代理,运维熟悉度高)。中小团队直接用 Nginx 即可:监听 443 ssl,proxy_pass http://127.0.0.1:6081,并 proxy_set_header X-Forwarded-Proto https。需要注意:Varnish 会把 X-Forwarded-Proto 透传给后端,应用层需识别该头判断 HTTPS,否则会在生成绝对链接时返回 http 引发混合内容。

四、命中率优化与 Vary 控制

新部署的 Varnish 命中率常常只有 30% 到 40%,主要原因有三:后端返回的 Set-Cookie 默认让 Varnish 不缓存;Vary: User-Agent 把 cache key 按 UA 分裂,命中率断崖式下跌;请求路径包含 query string,每次请求都被认为是不同对象。

针对性策略是在 vcl_backend_response 中针对静态资源后缀显式 unset beresp.http.Set-Cookie 并设置较长的 TTL,同时用 regsuballVary 响应头中的 User-Agent 字段移除,避免按浏览器版本分裂缓存。这两步做完后,多数站点的命中率会从 30% 跃升到 80% 以上。但要注意:不要对动态接口直接 unset Set-Cookie,会导致用户会话状态丢失,影响登录与购物车功能。

对 WordPress 站点,建议同时检查源站缓存配合,可参考 WordPress W3 Total Cache 调优实战 中关于浏览器缓存与边缘缓存协作的章节,避免与 Varnish 的 TTL 冲突。更多 WordPress 加速场景可在 WordPress 分类 下查阅相关内容。

五、PURGE 接口与发布回调

应用层发布新内容后必须主动告知 Varnish 清缓存:

curl -X PURGE http://127.0.0.1:6081/article/12345

PURGE 仅清精确匹配的 URL。需要按 tag 清缓存可用 xkey 模块:在响应中加上 xkey 头列出标签,清缓存时带 xkey 请求头即可。这种”按 tag 批量清”在 WordPress 这类内容关联复杂的场景下尤其好用。

六、监控与排障

Varnish 提供 varnishstatvarnishlogvarnishtop 三个核心工具:分别用来看命中率与内存、按请求查完整事件链、实时统计请求最多的 URL。生产环境把 varnishstat -1 -j 通过 telegraf 推到 Prometheus,关键指标:命中率 MAIN.cache_hit / (cache_hit + cache_miss)、内存淘汰 MAIN.n_lru_nuked、Backend 繁忙 MAIN.backend_busy

常见故障:内存淘汰频繁时增大 -s malloc;Backend 连续 503 时检查健康检查 URL;PURGE 不生效时检查 ACL。跨境回源链路异常可结合 美国 VPS 部署教程 中的 MTR 命令逐跳定位。

七、Grace 与 Saint 模式

Varnish 有两个独特的可用性特性:Grace 模式与 Saint 模式。Grace 模式允许在源站短暂不可用时继续返回过期但仍然存在的对象。配置示例:

sub vcl_backend_response { set beresp.grace = 1h; }

Saint 模式则在源站连续返回 5xx 时把该 Backend 暂时拉黑,避免雪崩。两者组合后即便后端应用层重启,前端用户感知通常仍能维持高可用。建议定期模拟后端宕机 10 分钟,看用户侧是否保持无感知。

总结与建议

自建 Varnish 反向代理缓存 的核心是”在应用前面加一层精确可控的缓存”,不要试图把它当作万能加速方案。建议中小团队先用默认配置跑两周观察命中率,再逐步引入 xkey、Backend 健康检查与监控告警。如果你的业务体量较小,可以把 Varnish 与已有主机直接合部署在同一台 VPS;如果体量较大,可考虑把 Varnish 单独部署在内存较多的服务器并通过内网与应用通信。整体来看,Varnish 适合作为应用层与 CDN 之间的二级缓存,能在节省费用的同时显著降低 P99 延迟。对希望长期掌控边缘逻辑的团队,把 Varnish 与监控告警、Grace 模式、自动 Purge 流程组合在一起后,往往能拿到接近商业 CDN 的体验。日常运维中,把 VCL 文件纳入 Git 仓库、把命中率指标接入 Prometheus、把发布流水线与 PURGE 接口联动这三件事都做完后,自建缓存层就能像云服务一样稳定运行而无需每天人工照看。最后再次建议:把 Varnish 当作整体加速方案的一环而不是全部,与上层 CDN、下层应用缓存协同推荐才能拿到最佳效果,如果你需要更可控的边缘逻辑也可以考虑在 Varnish 之上叠加自研网关。

发表评论