用于按需域/多租户的 Varnish 缓存

Varnish caching for on demand domains / Multitenancy

我一直在尝试使用 Caddy 和清漆设置自定义 CDN。这个想法是按需生成 SSL 证书,然后将其传递给清漆,清漆进一步将其发送到作为 nodejs 应用程序的后端服务器。如果请求匹配,则清漆 returns 缓存结果,否则获取新数据。 图中描述了工作 flow diagram

以下是相应的文件: docker-compose.yml

version: '3.7'

networks:
  web:
    external: true
  internal:
    external: false
    driver: bridge

services:
 caddy:
    image: caddy
    container_name: caddy
    restart: unless-stopped
    ports:
      - "8080:8080"
      - "80:80"
      - "443:443"
    volumes:
      - $PWD/Caddyfile:/etc/caddy/Caddyfile
      - $PWD/site:/srv
      - caddy_data:/data
      - caddy_config:/config
    networks:
      - web

 varnish:
    container_name: varnish
    image: varnish:stable
    restart: unless-stopped
    volumes:
      - $PWD/data/varnish/default.vcl:/etc/varnish/default.vcl
    networks:
      - web
      - internal
volumes:
  caddy_data:
    external: true
  caddy_config:

Caddyfile

{
    on_demand_tls {
        ask      https://check-domain-URL
    }
}

https:// {

tls {
    on_demand
}                          

reverse_proxy varnish:80 {
                header_up Host {host}  # Won't work with another value or transparent preset
                header_up X-Forwarded-Host {host}
                header_up X-Real-IP {remote}
                header_up X-Forwarded-For {remote}
                header_up X-Forwarded-Proto {scheme}
                header_up X-Caddy-Forwarded 1
                header_down Cache-Control "public, max-age=31536000"
}

header /_next/static/* {
Cache-Control "public, max-age=31536000, immutable"
}
}

:8080 {
reverse_proxy backend-address:3000
}

default.vcl

vcl 4.0;

backend default {
    .host = "caddy";
    .port = "8080";
}

sub vcl_deliver
{
    # Insert Diagnostic header to show Hit or Miss
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
        set resp.http.X-Cache-Hits = obj.hits;
    }
    else {
        set resp.http.X-Cache = "MISS";
    }

}

sub vcl_backend_response {
    set beresp.ttl = 10s;
    set beresp.grace = 1h;

}

一切正常

  1. 正在生成 SSL 证书
  2. 代理正在运行
  3. Varnish 正在返回结果
  4. 代理正在获取后端

唯一的问题是 Varnish Cache 总是 miss,这是它应该做的一件事 我已经尝试了所有方法,但看起来清漆将每个请求都视为新请求。 有什么想法吗?

为了理解您收到缓存未命中的原因,您需要了解 built-in VCL。

这是在后台执行的VCL代码。请查看以下解释此内容的教程:https://www.varnish-software.com/developers/tutorials/varnish-builtin-vcl/.

Built-in VCL缓存绕过总结

我总结一下Varnish不缓存的标准情况:

  1. 当请求方法不是GETHEAD
  2. 当请求包含 Authorization header
  3. 当请求包含 Cookie header
  4. 当响应包含 Set-Cookie header
  5. 由于Expiresheader或max-age=0s-maxage=0Cache-Controlheader[=中响应TTL为零时58=]
  6. 当响应在 Cache-Control header
  7. 中包含 privateno-cacheno-store
  8. 当有 Vary: * 响应时 header

正在使用 varnishlog

检查缓存 miss/bypass

找出缓存未命中原因或绕过缓存原因的一种简单方法是使用 varnishlog.

您可以运行以下命令来检查主页的日志:

sudo varnishlog -g request -q "ReqUrl eq '/'"

Please change / into the desire URL.

写VCL来补偿

如果您的应用程序不符合 built-in VCL 规范,您将不得不编写一些 VCL 代码来弥补这一点。

在大多数情况下,它会剥离跟踪 cookie 或定义哪些 URL 模式应绕过缓存,同时强制在所有其他页面上进行缓存查找。

Have a look at the logs to figure out what's what and if you need help, just add a log transaction to your question and I'll help you out.