Varnish HTTP 缓存服务器完全指南

想象一个智能仓库管理员,常卖的货物他直接放在门口(缓存),客户来了不用进仓库就能取走。Varnish 就是这个"智能仓库管理员",让 Web 服务器减轻负载,用户访问更快!


📑 目录

  1. [什么是 Varnish?](#什么是 Varnish?)
  2. 名词解释(命令与概念)
  3. [Varnish 架构](#Varnish 架构)
  4. [Varnish 配置详解](#Varnish 配置详解)
  5. [Varnish 部署实战](#Varnish 部署实战)
  6. [Varnish 缓存策略](#Varnish 缓存策略)
  7. [Purge 与 Ban:缓存失效](#Purge 与 Ban:缓存失效)
  8. [Varnish 管理工具](#Varnish 管理工具)
  9. 性能优化
  10. 总结与官方参考

🎯 什么是 Varnish?

核心概念

Varnish 是一个高性能的 HTTP 加速器,也被称为反向代理缓存服务器,专注于缓存 Web 内容以减轻后端服务器负载。
✅ 缓存命中
❌ 缓存未命中
👤 客户端
📦 请求资源?
🚀 Varnish

直接返回
🔄 Varnish

请求后端

并缓存
🖥️ 后端服务器

Tomcat/Apache
⚡ 快速响应

减轻后端负载

为什么需要缓存? 后端每次动态生成页面会占用 CPU、数据库;把不变或少变的内容放在 Varnish,同一内容只算一次、卖多次,延迟低、后端压力小。

生活类比

  • Varnish = 商场的"快速提货区"
  • 缓存命中 = 货物在快速提货区,直接拿走
  • 缓存未命中 = 需要去后面的仓库取货
  • 后端服务器 = 仓库,存储所有商品

Varnish vs 其他缓存方案

为什么选 Varnish 做专职缓存? 内存管理、哈希与锁针对缓存场景优化,VCL 可在不重启下加载新策略;Nginx 更偏「全能网关」,缓存只是其一;Squid 历史久、功能多但配置重。

特性 Varnish Squid Nginx
定位 专用缓存 代理+缓存 反向代理
性能 极高 中等
配置语言 VCL 配置文件 配置文件
缓存粒度 细粒度 粗粒度 粗粒度
生活类比 专职快递员 老式综合商店 现代购物中心

与其他软件对比(扩展)

下面从「反向代理 / 缓存 / 网关」角度,把 Varnish 与常见方案放在一起对比,便于按场景选型。
选型
🎯 要专职 HTTP 缓存?
✅ 选 Varnish
已有 Nginx/要一体化?
✅ Nginx proxy_cache
要边缘/防 DDoS?
✅ CDN
要正向代理/传统代理?
✅ Squid
要应用层 KV 缓存?
✅ Redis/Memcached

软件 定位 缓存能力 性能 配置/扩展 典型场景 与 Varnish 选型建议
Varnish 专用 HTTP 反向代理缓存 极强:VCL、purge/ban、grace、细粒度键 极高 VCL、热加载 站前缓存、API 缓存、减轻后端 专职缓存、高并发、可编程策略时首选。
Nginx 反向代理 + Web 服务器 + 缓存 中等:proxy_cache、proxy_cache_key 等 配置文件、Lua 等 负载均衡、动静分离、简单缓存 已有 Nginx、缓存需求不复杂时用 Nginx 即可;要更强缓存与策略用 Varnish。
Squid 正向/反向代理 + 缓存 强:ACL、refresh_pattern、purge 中等 配置文件(较复杂) 正向代理、企业上网缓存、传统反向缓存 要正向代理或已有 Squid 运维经验时可保留;新项目做反向缓存更推荐 Varnish。
Apache Traffic Server 反向代理 + 缓存(Apache 系) 强:插件、规则、ESI 配置文件、插件 大流量 CDN 节点、运营商级缓存 与 Varnish 同属「专职缓存」;ATS 偏 CDN 与插件生态,Varnish 偏 VCL 与自建控制。
Caddy 自动 HTTPS 的反向代理/Web 服务器 弱:无内置 HTTP 缓存 Caddyfile、简单 自动证书、简单反向代理 不做 HTTP 页面缓存;要缓存需前置 Varnish 或 Nginx。
HAProxy 负载均衡 + 四层/七层代理 无:不缓存响应 极高(四层/七层转发) 配置文件 负载均衡、高可用、SSL 终结 只做分流与高可用;缓存层用 Varnish/Nginx 放在 HAProxy 后面。
CDN(Cloudflare/阿里云等) 边缘加速 + 安全 强:边缘节点、就近命中、防 DDoS 依赖节点与回源 控制台/API 静态资源、全站加速、防攻击 就近、免运维、按量付费 用 CDN;要自建、数据不出域、策略完全可控用 Varnish。
Redis / Memcached 应用层 KV 缓存 非 HTTP:键值存储,由应用读写 极高(内存) 应用代码 Session、接口结果、热点数据 应用内缓存,不是 HTTP 反向缓存;可与 Varnish 并存:Varnish 缓存页面/接口响应,Redis 存 Session 等。

生活类比小结

  • Varnish:商场门口专职「快速提货区」管理员,只干缓存这一件事且干得极好。
  • Nginx:商场大门+问询台+小仓库,啥都能干,仓库只是其中一块。
  • Squid:老牌批发仓库,既能对外送货(反向)也能帮内部代购(正向),规矩多、配置厚。
  • CDN:连锁店在各地开分店,顾客就近取货;总店(源站)前还可以再放一个 Varnish 做「总店门口提货区」。

📖 名词解释(命令与概念)

常用命令

命令/工具 说明 生活类比 为什么常用?
varnishd Varnish 守护进程,真正干活的进程 仓库的「总控室」:启动后负责接单、查库存、叫仓库取货 为什么叫 daemon?后台常驻运行,不依赖终端;所有请求都由它处理。
varnishadm 管理接口,通过 CLI 与 varnishd 对话 经理用对讲机跟总控室说话:加载新规则、清缓存、看状态 为什么用 127.0.0.1:6082?管理口只监听本机,避免被外网误操作或攻击。
varnishstat 实时统计计数器(命中、未命中、连接数等) 仓库门口的「今日提货/入库」大屏 为什么看 HIT/MISS?命中率高说明门口货多、回仓库少,后端压力小、响应快。
varnishlog 按请求/会话输出详细日志(可过滤) 每笔交易的流水单:谁、要了什么、命中还是去仓库取的 为什么调试用?能精确看到某请求走了 lookup/pass/fetch 哪条路径。
varnishncsa 把日志转成 NCSA 兼容格式(类似 Apache access_log) 把流水单整理成「标准报表」给分析工具用 为什么需要?很多监控、ELK 等只认 NCSA 格式,便于统一分析。

核心概念

概念 说明 生活类比 为什么重要?
VCL Varnish Configuration Language,Varnish 专用配置语言 仓库的「作业手册」:什么货放门口、什么必须去仓库取、谁可以要求清空某格 为什么不用普通配置文件?缓存策略复杂(按 URL、Cookie、头、后端健康),需要条件分支和正则,VCL 专为此设计。
backend 后端服务器定义(host、port、探针等) 仓库的「供应商/仓库房号」:去哪取货、多久算超时、怎么检查供应商是否在线 为什么有 probe?后端挂了若不知道,请求会一直打到死节点;探针定期探测,自动摘除故障后端。
director 多个 backend 的负载均衡器(轮询、随机等) 多个仓库入口的「调度员」:轮流或随机选一个仓库取货 为什么用 director?单后端易成瓶颈;多后端分流并配合 probe 可做高可用。
TTL Time To Live,对象在缓存中的存活时间 门口货架的「保质期」:过了就认为过期,下次要就去仓库重新取 为什么不能无限大?内容会更新(如新闻、价格),TTL 太长会一直卖旧货。
grace 对象过期后仍可被使用的一段时间(常在后端故障时) 仓库补货延迟时,「先卖库存里过期的」顶一阵,不直接报错 为什么有用?后端挂了或很慢时,返回稍旧的缓存总比 502 好,用户体验更稳。
keep 在 TTL 之外多保留一段时间,用于发 304 条件请求刷新 过期了但还留着「样品」,用来问后端:这批货有没有新版本?有就更新,没有就继续用样品 为什么能省带宽?304 只传头不传体,后端说「没变」就继续用缓存,减少回源流量。
pass 不查缓存,直接转发到后端且不缓存响应 客户要的是「定制/生鲜」,不放进门口货架,每次都去仓库现取 为什么 POST/登录等要 pass?会改状态或带 Cookie,缓存会错;必须实时走后端。
pipe 把客户端与后端之间打成「管道」,Varnish 只做 TCP 中转 客户和仓库直接「连麦」,管理员只负责接通,不拆包、不缓存 为什么 WebSocket 等要用 pipe?非 HTTP 或长连接,Varnish 不解析内容,直接透传更合适。
hash 查缓存:先算缓存键再 lookup,命中则交付、未命中则 fetch 按「单号」(URL+Host 等)查门口有没有货,有就交付,没有就去仓库取并上架 为什么只缓存 GET/HEAD?规范上 GET 幂等、可缓存;POST 等会改数据,不能当同一份货反复卖。
HIT 缓存命中,直接从缓存返回 门口就有货,直接提走 为什么追求高 HIT?命中时无需问后端,延迟低、后端负载小。
MISS 缓存未命中,需从后端取并可选缓存 门口没有,去仓库取,取完可以放一份到门口 为什么有 hit-for-pass?某 URL 被标记为「永远不缓存」时,会记一条「不缓存」结果,避免反复去后端问。
purge 用 HTTP PURGE 等方法删除缓存中单个对象(精确 URL) 经理说:「把 3 号货架第 2 格清空」------只清这一格 为什么只支持单 URL?语义简单、实现简单;精确失效时用。
ban 用表达式(如正则)让一批对象在下次被命中时视为失效 经理说:「所有 3 号货架上的东西都别卖了」------按规则批量失效 为什么 ban 是「下次命中时」?不立刻扫全缓存,避免卡顿;命中时再检查 ban 列表,匹配就不交付、去后端取。
stevedore Varnish 的存储引擎(如 malloc、file) 门口货架用「内存」(malloc) 还是「磁盘文件」(file):内存快但重启丢,文件可持久、容量大 为什么有 file?内存贵且有限;大容量缓存用 file 存到 SSD/磁盘,重启后还能保留部分缓存。

相近概念对比

对比项 含义 何时用 生活类比
pass vs pipe pass:走 HTTP,Varnish 解析并转发,但不缓存;pipe:纯 TCP 隧道,不解析 普通 HTTP 但不缓存用 pass;WebSocket、CONNECT 等用 pipe pass = 管理员代你去仓库取货并交给你;pipe = 管理员只给你接一条直通仓库的电话线
hash vs pass hash:查缓存,命中交付/未命中取后端;pass:不查缓存,直接后端 可缓存请求用 hash;登录、POST、管理后台等用 pass hash = 先看门口有没有;pass = 一律去仓库,不摆门口
purge vs ban purge:删一个 URL 的缓存;ban:按表达式让一批对象失效(下次命中时生效) 精确删一条用 purge;删整站/某目录/某后缀用 ban purge = 清空 1 个格子;ban = 贴告示「这类货一律不准从门口卖」
grace vs keep grace:过期后还能当「保底」用;keep:过期后多留一段时间,用于发 304 刷新 防后端故障用 grace;想省带宽、支持 304 用 keep grace = 断货时先卖临期品;keep = 留样品方便问供应商「有没有新款」

🏗️ Varnish 架构

工作原理

为什么请求要先进 vcl_recv? 这里是「入口」,决定这条请求是查缓存(hash)、绕开缓存(pass) 还是打管道(pipe),后续所有步骤都由此分支决定。
🔄 Varnish 工作流程
🔑 lookup
➡️ pass
🔌 pipe


👤 客户端请求
📥 VCL 接收

vcl_recv
📌 缓存策略?
📂 查询缓存
🖥️ 直接转发后端
📡 管道直连
✅ 命中?
📤 返回缓存
🔄 fetch 后端
💾 缓存并返回
📤 不缓存返回
📤 直连返回

VCL (Varnish Configuration Language)

VCL 是 Varnish 的专用配置语言,用于定义缓存策略。VCL 会被编译成 C 并加载到 worker 中执行,所以修改后需要「加载 + 使用」新 VCL 才能生效。

为什么 VCL 没有循环? 设计成「请求进来 → 一串判断 → return 一个动作」,避免复杂逻辑拖慢每请求的处理速度;复杂逻辑可放在 VMOD(C 扩展)里。
缓存
不缓存


📋 VCL 状态机
📥 vcl_recv

请求接收
📌 请求类型?
🔢 vcl_hash

计算哈希
➡️ vcl_pass

直接转发
🔍 查找缓存
✅ 命中?
✅ vcl_hit

返回缓存
❌ vcl_miss

去后端
📥 vcl_backend_response

从后端取回后处理
📤 vcl_deliver

交付

VCL 内置子例程(subroutines)

子例程 说明 使用场景 为什么在这个阶段?
vcl_recv 请求接收后第一个入口 决定 return(hash)/pass/pipe/purge/synth 必须先决定「查不查缓存、走不走管道」,后面才能分支。
vcl_hash 计算缓存键(可追加 hash_data) 自定义缓存键(如按设备类型区分) 键决定「同一请求是否命中同一对象」;默认用 req.url + Host 等。
vcl_hit 缓存命中时 可改为 pass 或 miss 重取 命中后通常直接 deliver,少数场景要强制刷新才改。
vcl_miss 缓存未命中时 通常 return(fetch),去后端取 未命中就必须去后端,fetch 后会进入 vcl_backend_response。
vcl_backend_response 从后端拿到响应后 设 TTL、grace、keep、是否缓存 后端响应在这里才能看到状态码、头、体,决定存不存、存多久。
vcl_backend_error 后端错误(超时、5xx)时 合成错误页或重试 为什么单独?后端挂了时可能想返回友好页或从别的后端重试。
vcl_deliver 即将把响应交给客户端前 加调试头(如 X-Cache: HIT/MISS) 最后一环,可改响应头不改体,便于排查。
vcl_synth 使用 synthetic() 生成响应时 自定义错误页、重定向 不走后端,由 Varnish 直接返回内容。

⚙️ Varnish 配置详解

基础配置示例

vcl 复制代码
# /etc/varnish/default.vcl

vcl 4.1;

import std;

# 后端服务器定义(为什么要有 .probe?后端挂了要自动摘除,避免请求一直打向死节点)
backend web1 {
    .host = "192.168.1.20";
    .port = "80";
    .probe = {
        .url = "/";
        .timeout = 2s;
        .interval = 5s;
        .window = 5;
        .threshold = 3;
    }
}

backend web2 {
    .host = "192.168.1.21";
    .port = "80";
    .probe = {
        .url = "/";
        .timeout = 2s;
        .interval = 5s;
        .window = 5;
        .threshold = 3;
    }
}

# 定义 directors
sub vcl_init {
    # 轮询负载均衡
    new web_servers = directors.round_robin();
    web_servers.add_backend(web1);
    web_servers.add_backend(web2);
}

# 请求接收
sub vcl_recv {
    # 设置后端
    set req.backend_hint = web_servers;

    # 只缓存 GET 和 HEAD 请求
    if (req.method != "GET" && req.method != "HEAD") {
        return (pass);
    }

    # 不缓存特定路径
    if (req.url ~ "^/admin") {
        return (pass);
    }

    # 移除端口号
    set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");

    # 去除 www
    if (req.http.Host ~ "^(www\.).*") {
        set req.http.Host = regsub(req.http.Host, "^www\.", "");
    }

    return (hash);
}

# 缓存命中
sub vcl_hit {
    return (deliver);
}

# 缓存未命中
sub vcl_miss {
    return (fetch);
}

# 从后端取回响应后的处理(Varnish 4.x 为 vcl_backend_response,不再使用 vcl_fetch)
sub vcl_backend_response {
    # 设置缓存时长
    if (beresp.http.Cache-Control ~ "max-age") {
        unset beresp.http.Set-Cookie;
        set beresp.ttl = std.duration(beresp.http.Cache-Control, "max-age");
    }

    # 不缓存有 Set-Cookie 的响应(特殊情况除外)
    if (beresp.http.Set-Cookie) {
        if (req.url ~ "^/api") {
            unset beresp.http.Set-Cookie;
        } else {
            return (deliver);
        }
    }

    return (deliver);
}

# 交付内容
sub vcl_deliver {
    # 添加调试头
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
    } else {
        set resp.http.X-Cache = "MISS";
    }

    return (deliver);
}

VCL 语法规则

为什么 VCL 用 ~ 做匹配? 沿用 Perl 习惯,~ 表示正则匹配;!~ 表示不匹配。字符串用双引号,长字符串可用 {"..."} 含换行。

规则 说明 示例 为什么?
赋值 set set req.http.Host = "example.com" 请求/响应头、超时等都可改,决定后续行为。
取消 unset unset beresp.http.Set-Cookie 去掉 Set-Cookie 后响应才敢缓存,否则每用户不同。
正则匹配 ~ if (req.url ~ "\.jpg$") URL、Host、User-Agent 等常用正则区分策略。
取反匹配 !~ if (req.url !~ "^/static") 排除某类请求(如非静态一律 pass)。
字符串替换 regsub / regsuball regsub(req.url, "\.jpg$", ".png") 归一化 URL(如去端口、去 www)便于缓存键一致。
终止 return(action) return (hash) 每个子例程必须 return 一个动作,否则用默认行为。

🚀 Varnish 部署实战

安装 Varnish

为什么用包管理器安装? 便于升级、依赖统一、与 systemd 集成,生产环境一般不推荐手编。

bash 复制代码
# 1. 安装 Varnish(以 RHEL/CentOS 为例;Debian/Ubuntu 可用 apt install varnish)
yum install varnish -y

# 2. 开机自启并启动
systemctl enable varnish
systemctl start varnish

# 3. 检查状态(确认 Active: active (running))
systemctl status varnish

配置 Varnish

为什么监听 80 而管理口用 6082? 80 是用户流量入口;管理口单独端口且通常只绑 127.0.0.1,避免外网连上 varnishadm。为什么存储用 file? 内存(malloc) 快但重启即丢、容量受限于 RAM;file 可持久、容量大(如 10G),适合大缓存。

bash 复制代码
# /etc/varnish/varnish.params

# Varnish 监听地址(0.0.0.0:80 表示所有网卡 80 端口)
VARNISH_LISTEN_ADDRESS=0.0.0.0:80

# 管理接口(仅本机,用于 varnishadm)
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1:6082

# 存储:malloc 为纯内存;file 为文件(可持久、大容量)
VARNISH_STORAGE="file,/var/lib/varnish/varnish_storage.bin,1G"

# worker 线程数(根据 CPU 与并发调整)
VARNISH_WORKER_THREADS=500

# 日志路径
VARNISH_LOGFILE="/var/log/varnish/varnish.log"

启动并测试

bash 复制代码
# 1. 重启 Varnish(改 VCL 或 params 后通常需 restart)
systemctl restart varnish

# 2. 查看 Varnish 日志(进程/启动类)
tail -f /var/log/varnish/varnish.log

# 3. 管理 CLI:ping 确认与管理进程连通
varnishadm ping

# 4. 实时统计(HIT/MISS、连接数等)
varnishstat

# 5. 请求级日志(调试用,可按 X-Varnish 等过滤)
varnishlog

为什么改 VCL 后可以不重启进程?varnishadm vcl.load + varnishadm vcl.use 加载并切换新 VCL,旧连接按旧逻辑跑完,新请求用新逻辑,实现「热加载」。


📊 Varnish 缓存策略

缓存决策树

GET/HEAD
POST/PUT/...






👤 客户端请求
📌 请求方法?
📦 可缓存?
➡️ 直接转发

pass
🔢 计算哈希

hash
📂 缓存中存在?
✅ 缓存命中

HIT
❌ 缓存未命中

MISS
🖥️ 从后端获取
📦 响应可缓存?
💾 缓存并返回
📤 不缓存直接返回

缓存最佳实践

策略 说明 VCL 示例 生活类比
只缓存 GET POST 等不缓存 if (req.method != "GET") return (pass); 只把「看货」当可缓存,「下单」每次都去仓库。
忽略 Cookie 静态资源忽略 cookie unset req.http.Cookie; 图片/CSS/JS 不按人区分,去掉 Cookie 后同一 URL 共用一个缓存。
不缓存管理 管理页面不缓存 if (req.url ~ "^/admin") return (pass); 经理办公室的货不能放门口卖,必须每次进办公室取。
强制刷新 PURGE 方法刷新缓存 if (req.method == "PURGE") { return (purge); } 经理说「3 号格清空」立即执行。

为什么只缓存 GET/HEAD? HTTP 语义里 GET/HEAD 是幂等的、不修改资源,可安全缓存;POST/PUT/DELETE 会改状态,缓存会导致重复提交或数据错乱。


🗑️ Purge 与 Ban:缓存失效

内容更新后需要让缓存失效,Varnish 提供 purge (精确删一条)和 ban(按条件批量失效)两种方式,对应「名词解释」中的对比。

Purge vs Ban 对比

📋 Ban
表达式/正则
varnishadm / HTTP BAN
下次命中时失效
🔪 Purge
单 URL
HTTP PURGE
立即删除

维度 Purge Ban
作用范围 单个 URL(及 Vary 变体) 匹配表达式的所有对象
是否支持正则 否,精确 URL 是,如 req.url ~ "\.png$"
生效时机 立即从缓存移除 对象下次被命中时再判断,匹配则不交付、回源取
典型用法 发布新文章后删首页缓存 全站换主题后 ban 所有 .css、或 ban obj.http.url ~ "/news/"

为什么 ban 是「下次命中时」? 若每次 ban 都扫描全缓存,大缓存会卡顿;改为命中时再检查 ban 列表,CPU 分散到各请求,延迟更可控。需要立刻腾空间时可配合 TTL 或限制缓存大小。

Purge 示例(VCL)

只允许本机和内网执行 PURGE,避免被滥用:

vcl 复制代码
acl purge_allowed {
    "localhost";
    "127.0.0.1";
    "192.168.0.0"/24;
}

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

为什么 PURGE 要加 ACL? PURGE 会删缓存,若对公网开放,攻击者可反复 purge 导致缓存雪崩、全部回源,所以只允许可信 IP。

Ban 示例(命令行 + 可选 HTTP BAN)

bash 复制代码
# 清除所有 .png(按 URL 正则)
varnishadm ban "req.url ~ '\.png$'"

# 清除某主机的某路径
varnishadm ban "req.http.host == 'www.example.com' && req.url ~ '^/api/'"

# 查看当前 ban 列表
varnishadm ban.list

通过 HTTP 发 BAN(需在 VCL 里实现,例如用 std.ban()):

vcl 复制代码
import std;

sub vcl_recv {
    if (req.method == "BAN") {
        if (!client.ip ~ purge_allowed) {
            return (synth(403, "Forbidden"));
        }
        if (std.ban("req.http.host == " + req.http.host + " && req.url == " + req.url)) {
            return (synth(200, "Ban added"));
        }
        return (synth(400, std.ban_error()));
    }
}

为什么 ban 用 obj. 更友好? * ban lurker 后台线程只处理只涉及 obj.* 的 ban,能持续清理匹配对象;若 ban 里只用 req.*,lurker 无法用请求上下文,只能等请求命中时再判,ban 列表可能积压。


🔧 Varnish 管理工具

varnishadm 命令

为什么 vcl.load 要起个名字? 可同时加载多份 VCL(如 new_config、backup),用名字区分;切换时 vcl.use new_config 指定用哪一份,便于回滚。

bash 复制代码
# 查看与管理进程是否连通
varnishadm ping

# 查看运行参数(线程数、storage 等)
varnishadm param.show

# 加载新 VCL(名字 + 来源:default 表示用 -f 指定的主文件)
varnishadm vcl.load new_config default.vcl

# 切换为刚加载的 VCL(新请求立即用新配置)
varnishadm vcl.use new_config

# 按条件 ban(正则),不是删单条 URL
varnishadm ban req.url "^/static/.*"

# 丢弃未使用的 VCL 副本(释放引用)
varnishadm vcl.discard old_config

varnishstat 监控

为什么关注 cache_hit 与 cache_miss? 命中多说明缓存有效、后端压力小;命中率 = cache_hit / (cache_hit + cache_miss),通常希望 > 90% 以上(视业务而定)。

bash 复制代码
# 实时统计(每秒刷新)
varnishstat

# 单次输出后退出(便于脚本采集)
varnishstat -1

# 只看某计数器
varnishstat -1 -f cache_hit -f cache_miss
常用计数器 含义 生活类比
MAIN.cache_hit 缓存命中次数 门口直接提货次数
MAIN.cache_miss 缓存未命中次数 去仓库取货次数
MAIN.sess_conn 接受的客户端连接数 接待的客户数
MGT.uptime 进程运行时长 仓库开门了多久

💡 性能优化

为什么线程池要设 min/max? min 保证始终有足够 worker 应对突发;max 防止连接爆炸时无限开线程拖垮机器。workspace 调大可处理更大请求/响应头,但占内存。

调优参数

bash 复制代码
# /etc/systemd/system/varnish.service.d/custom.conf

[Service]
# 增加文件描述符限制
LimitNOFILE=131072

# 增加线程数
ExecStart=
ExecStart=/usr/sbin/varnishd \
    -a :80 \
    -T localhost:6082 \
    -f /etc/varnish/default.vcl \
    -s file,/var/lib/varnish/varnish_storage.bin,10G \
    -p thread_pool_min=200 \
    -p thread_pool_max=4000 \
    -p workspace_client=128k \
    -p workspace_backend=128k

缓存命中率优化

为什么命中率重要? 命中时无需问后端,延迟低、带宽省、后端 CPU 省;命中率每提高一截,后端负载就明显下降。
📈 提高缓存命中率
⏱️ 增加 TTL
📁 缓存静态资源
🔧 忽略动态参数
🛡️ 使用 grace 模式
⬇️ 减少回源
🖥️ 后端故障时用旧缓存保底

VCL 缓存优化配置

vcl 复制代码
sub vcl_backend_response {
    # 对于图片、CSS、JS,缓存 1 天
    if (bereq.url ~ "\.(jpg|jpeg|png|gif|css|js)$") {
        set beresp.ttl = 86400s;
        unset beresp.http.Set-Cookie;
    }

    # 对于 HTML,缓存 1 小时
    if (bereq.url ~ "\.html$") {
        set beresp.ttl = 3600s;
    }

    # grace 模式:后端故障时使用旧缓存
    set beresp.grace = 3600s;

    return (deliver);
}

🎯 总结与官方参考

Varnish 是专业的 HTTP 缓存服务器,能够大幅提升 Web 性能和减轻后端负载。

核心要点记忆口诀

  • Varnish 专缓存,性能极高是王道
  • VCL 语言强,灵活配置没商量
  • 动静要分离,静态资源缓存好
  • grace 模式妙,后端故障能保底
  • 监控要做好,命中率要盯牢

生活类比总结

  • Varnish = 智能仓库管理员
  • 缓存命中 = 快速提货区直接拿走
  • 缓存未命中 = 去仓库取货
  • grace 模式 = 仓库补货时先卖库存
  • ban 清理 = 主动清理过期商品

官方文档与延伸阅读

资源 说明
Varnish Cache 官方文档 安装、配置、VCL 参考
VCL 4.1 参考 语法、变量、子例程、backend、probe
Purging and banning Purge 与 Ban 的官方说明
varnishd 参数 启动参数、storage、线程等

相近方案简要对比

更完整的对比见前文 与其他软件对比(扩展)

方案 适用场景 与 Varnish 对比
Nginx proxy_cache 已有 Nginx、缓存需求不复杂 配置简单、无需单独进程;缓存能力与灵活性不如 Varnish。
Squid 传统正向/反向代理 + 缓存 功能多、历史久;性能与配置灵活性一般不如 Varnish。
Apache Traffic Server 大流量、CDN 节点、插件化 同属高性能缓存;ATS 偏 CDN/插件,Varnish 偏 VCL 自建。
Caddy 自动 HTTPS、简单反向代理 无内置 HTTP 缓存;做缓存需前挂 Varnish 或 Nginx。
HAProxy 负载均衡、高可用、SSL 终结 不缓存;常与 Varnish 搭配:HAProxy 分流,Varnish 做缓存层。
CDN(Cloudflare、阿里云等) 静态资源、全站加速、防 DDoS 边缘节点、就近命中;Varnish 自建、可控、无按量费用。
Redis / Memcached Session、接口结果、热点 KV 应用层缓存,非 HTTP 反向缓存;可与 Varnish 并存(Varnish 缓存页面,Redis 存 Session 等)。

最后提醒:Varnish 缓存虽好,但动态内容要谨慎!Session、管理页面、带 Cookie 的个性化内容等绝对不能缓存;否则会出现用户 A 看到用户 B 的数据等严重问题。

相关推荐
爱凤的小光2 小时前
VisionMaster软件---脚本梳理
java·服务器·网络
daad77710 小时前
USB_抓包
linux·运维·服务器
闻哥11 小时前
Redis事务详解
java·数据库·spring boot·redis·缓存·面试
未来之窗软件服务11 小时前
服务器运维(四十)日服务器linux-ps分析工具—东方仙盟
linux·运维·服务器·服务器运维·仙盟创梦ide·东方仙盟
Trouvaille ~13 小时前
【Linux】数据链路层与以太网详解:从 MAC 地址到 ARP 的完整指南
linux·运维·服务器·网络·以太网·数据链路层·arp
xiaoliuliu1234513 小时前
Xftp-7.0.0109p文件传输安装步骤详解(附FTP/SFTP连接与文件传输教程)
运维·服务器
小鸡食米13 小时前
LVS(Linux Virtual Server)
运维·服务器·网络
fyakm13 小时前
防范HTTP安全风险:CSRF、XSS等攻击与防御策略(含代码)
安全·http·csrf
码农阿豪13 小时前
解决HTTP 413错误:请求实体过大(Request Entity Too Large)的终极指南
网络·网络协议·http