手册:Varnish 缓存

This page is a translated version of the page Manual:Varnish caching and the translation is 88% complete.

Varnish 是一个轻量级、高效的反向代理服务器[1],它减少了为经常请求的页面提供服务所需的时间。

Varnish 是一种 HTTP 加速器,它存储由 Web 服务器提供的页面副本。 下次请求同一页面时,Varnish 将提供副本而不是从 Apache 服务器请求页面。 此缓存过程消除了 MediaWiki 再次重新生成同一页面的需要,从而极大地提高了性能。[2]

Varnish 具有专为用作 HTTP 加速器(反向代理)而设计的优势。 它将大部分缓存数据存储在内存中,与更大、更多用途的 Squid 包相比,它创建的磁盘文件和对文件系统的访问更少。 与 Squid 一样,它从缓存中向匿名 IP 用户提供经常请求的页面,而不是从原始 Web 服务器请求它们。 这减少了基本 MediaWiki 服务器的 CPU 使用率和数据库访问。

由于这种性能提升,MediaWiki 被设计为与网络缓存紧密集成,并在页面应从缓存中清除以便重新生成时通知 Squid 或 Varnish。

从 MediaWiki 的角度来看,正确配置的 Varnish 安装可以与其对应的 Squid 互换。

架构

下面概述了在单个服务器上设置 Varnish、Apache 和 MediaWiki 的示例。 一个更复杂的缓存策略可以在相同的 Varnish 缓存后面使用多个 Web 服务器(所有这些都可以看起来像一个主机)或者使用独立的服务器来传递 wiki 或图像内容。

外界

服务器

Varnish 加速器
w.x.y.z:80

Apache 服务器
127.0.0.1:80

对于外界,Varnish 似乎充当 Web 服务器。 实际上,它负责将请求传递给 Apache Web 服务器,但仅在必要时才传递。 在同一台服务器上运行的 Apache 只监听来自本地主机(127.0.0.1)的请求,而 Varnish 只监听服务器外部 IP 地址的请求。 这两个服务都在端口 80 上运行而没有冲突,因为每个服务都绑定到不同的 IP 地址。

配置 Varnish

以下配置适用于 Varnish 版本 4 及更高版本。

vcl 4.0;
# set default backend if no server cluster specified
backend default {
    .host = "127.0.0.1";
    .port = "8080";
    # .port = "80" led to issues with competing for the port with apache.
}

# access control list for "purge": open to only localhost and other local nodes
acl purge {
    "127.0.0.1";
}

# vcl_recv is called whenever a request is received 
sub vcl_recv {
        # Serve objects up to 2 minutes past their expiry if the backend
        # is slow to respond.
        # set req.grace = 120s;

        set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;

        set req.backend_hint= default;
 
        # This uses the ACL action called "purge". Basically if a request to
        # PURGE the cache comes from anywhere other than localhost, ignore it.
        if (req.method == "PURGE") {
            if (!client.ip ~ purge) {
                return (synth(405, "Not allowed."));
            } else {
                return (purge);
            }
        }
        
        # Pass requests from logged-in users directly.
        # Only detect cookies with "session" and "Token" in file name, otherwise nothing get cached.
        if (req.http.Authorization || req.http.Cookie ~ "([sS]ession|Token)=") {
            return (pass);
        } /* Not cacheable by default */
 
        # normalize Accept-Encoding to reduce vary
        if (req.http.Accept-Encoding) {
          if (req.http.User-Agent ~ "MSIE 6") {
            unset req.http.Accept-Encoding;
          } elsif (req.http.Accept-Encoding ~ "gzip") {
            set req.http.Accept-Encoding = "gzip";
          } elsif (req.http.Accept-Encoding ~ "deflate") {
            set req.http.Accept-Encoding = "deflate";
          } else {
            unset req.http.Accept-Encoding;
          }
        }
 
        return (hash);
}

sub vcl_pipe {
        # Note that only the first request to the backend will have
        # X-Forwarded-For set.  If you use X-Forwarded-For and want to
        # have it set for all requests, make sure to have:
        # set req.http.connection = "close";
 
        # This is otherwise not necessary if you do not do any request rewriting.
 
        set req.http.connection = "close";
}

# Called if the cache has a copy of the page.
sub vcl_hit {
        if (!obj.ttl > 0s) {
            return (pass);
        }
}

# Called after a document has been successfully retrieved from the backend.
sub vcl_backend_response {
        # Don't cache 50x responses
        if (beresp.status == 500 || beresp.status == 502 || beresp.status == 503 || beresp.status == 504) {
            set beresp.uncacheable = true;
            return (deliver);
        }   
 
        if (!beresp.ttl > 0s) {
          set beresp.uncacheable = true;
          return (deliver);
        }
 
        if (beresp.http.Set-Cookie) {
          set beresp.uncacheable = true;
          return (deliver);
        }
 
        if (beresp.http.Authorization && !beresp.http.Cache-Control ~ "public") {
          set beresp.uncacheable = true;
          return (deliver);
        }

        return (deliver);
}

配置 MediaWiki

由于 Varnish 正在执行来自本地主机的请求,Apache 将收到“127.0.0.1”作为直接远程地址。 但是,当 Varnish 将请求转发给 Apache 时,它被配置为添加“X-Forwarded-For”标头,以便保留来自外界的远程地址。 MediaWiki 必须配置为使用“X-Forwarded-For”标头才能在 special:recentchanges 中正确显示用户地址。

Squid 所需的配置与 Varnish 相同。 确保 LocalSettings.php 文件包含以下行:

$wgUseCdn = true;
$wgCdnServers = [ '127.0.0.1', '192.168.0.1' ];
//Use $wgCdnServersNoPurge if you don't want MediaWiki to purge modified pages
//$wgCdnServersNoPurge = [ '192.168.0.2' ];

请务必将“192.168.0.1”替换为您的 Varnish 缓存正在侦听的 IP 地址。 这些设置有两个目的:

  • 如果从 Varnish 缓存服务器收到请求,MediaWiki 日志需要显示用户的 IP 地址,而不是 Varnish 的 IP 地址。 特殊:最近更改中的每个编辑都被报告为“127.0.0.1”,这几乎是无用的;将该地址列为 Squid/Varnish 服务器会使 MediaWiki 忽略该 IP 地址,而是查看用户 IP 的“x-forwarded-for”标头。
  • 如果 wiki 上的页面或图像发生更改,MediaWiki 将向 $wgCdnServers 中列出的每个服务器发送通知,告诉它丢弃(清除)过时的存储页面。

$wgCdnServersNoPurge 用于需要保持在最近更改之外但不接收 HTTP 清除消息的地址。 例如,如果 Apache 和 Squid 分别位于 127.0.0.1 和同一台机器上的外部地址,则无需向 Apache 发送用于 Squid 的“清除”消息。 同样,如果 Squid 正在侦听多个地址,则只向其中一个发送“清除”。

另请参阅 Squid 配置设置了解与 Squid/Varnish 缓存相关的所有设置。

如果您使用 HTTPS,请务必将 $wgInternalServer 设置为与 $wgServer 相同的值,但使用 http:// 协议,以防止清除请求作为 HTTPS 发送,因为 Varnish 不支持 HTTPS。

If using $wgForceHTTPS , be sure to send request header "X-Forwarded-Proto: https" to suppress the redirect, otherwise disable $wgForceHTTPS to prevent redirect loops.

一些笔记

请注意,Varnish 是 Squid 的替代品,但不会替代完整 MediaWiki 缓存策略的其他部分,例如:

预编译的 PHP 代码
Apache 下 PHP 的默认行为是每次访问时加载和解释 PHP Web 脚本。 安装诸如 APC 之类的缓存(yum install php-pecl-apc,然后通过在 /etc/php.d/apc.ini 中设置 apc.shm_size=128 或更好)来分配内存可以大大减少 Apache 为 PHP 内容提供服务所需的 CPU 时间量。
本地化/国际化
默认情况下,MediaWiki 将创建一个巨大的 l10n_cache 数据库表并不断访问它——在“升级”到最新的 MediaWiki 版本后,数据库服务器上的负载可能会增加一倍以上。 设置 $wgLocalisationCacheConf 以强制将本地化信息存储到文件系统以解决此问题。
变量和会话数据
将 MediaWiki 侧边栏、命名空间列表或垃圾邮件黑名单等可变数据存储到内存缓存中将大大提高 MediaWiki 安装的速度。 强制用户登录数据存储在一个公共位置对于任何安装来说也是必不可少的,在这些安装中,多个可互换的 Apache 服务器隐藏在相同的 Varnish 缓存后面,为相同的 wiki 提供页面。 安装 Memcached 包并在 LocalSettings.php 中设置以下选项以强制用户登录信息和缓存变量都使用 Memcache:
$wgMainCacheType = CACHE_MEMCACHED;
$wgMemCachedServers = [ '127.0.0.1:11211' ];
请注意,如果您有多个服务器,则 localhost 地址需要替换为共享 Memcached 服务器的地址,该地址对于您站点上所有匹配的 Web 服务器必须相同。 这确保了将用户登录到集群中的一台服务器后,用户将登录到所有可互换 Web 服务器上的 wiki。

在许多情况下,有多种替代缓存方法会产生相同的结果。 参见 手册:缓存


Apache configuration

Log file

The Apache web server log, by default, shows only the address of the Varnish cache server, in this example "127.0.0.1:80"

Apache may be configured to log the original user's address by capturing "x-forwarded-for" information under a custom log file format.[3]

An example for Apache's httpd.conf to configure logging of x-forwarded-for is:

LogFormat "%{X-Forwarded-for}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" cached

Image hotlinking

If a site uses Apache's mod_rewrite to block attempts by other websites to hotlink images, this configuration will need to be removed and equivalent configuration added to Varnish's configuration files. Where an image server is located behind Varnish, typically 90% or more of common image requests never reach Apache and therefore will not be blocked by a "http_referer" check in Apache's configurations.


参见

參考資料