Jump to content

手册:文件缓存

From mediawiki.org
This page is a translated version of the page Manual:File cache and the translation is 98% complete.
Outdated translations are marked like this.

MediaWiki有一个缓存条目的HTML代码的可选缓存方案。

操作和使用

文件缓存只为匿名用户服务,他们看到的是相同的HTML渲染。 已登录用户不能用这个缓存,因为他们的页面包含了用户名、选择的皮肤等。

文件缓存是通过在LocalSettings.php中设置$wgUseFileCache $wgFileCacheDirectory 参数启用的:

$wgUseFileCache = true; // 默认: false
$wgFileCacheDirectory = "$IP/images/cache"; // 默认值:"{$wgUploadDirectory}/cache",等于"$IP/images/cache"

这将导致wiki的每个页面的渲染HTML网页存储在硬盘上的单个文件中。匿名用户的任何后续请求都不会通过再次呈现页面来满足,而是通过发送存储在磁盘上的HTML版本来满足。这节省了时间。

生成的HTML web文本存储在$wgFileCacheDirectory下的目录中的磁盘中,看起来有点像:

-rw-r--r-- 1 apache apache 57421 Jan  7 01:58 cache/0/04/P%C3%A1gina_principal.html
-rw-r--r-- 1 apache apache 29608 Jan  4 16:37 cache/1/17/P%C3%A1gina_Riscada.html
-rw-r--r-- 1 apache apache 21592 Jan  3 07:27 cache/1/1c/P%C3%A1gina_Duplicada.html
-rw-r--r-- 1 apache apache 36088 Jan  7 02:03 cache/2/24/P%C3%A1gina_principal_alternativa.html
-rw-r--r-- 1 apache apache 44205 Jan  7 06:10 cache/a/a4/P%C3%A1gina_linkada.html
-rw-r--r-- 1 apache apache 24686 Jan  3 07:27 cache/d/db/P%C3%A1gina_Invertida.html
-rw-r--r-- 1 apache apache 17222 Jan  3 06:28 cache/f/f0/P%C3%A1gina_n%C3%A3o_encontrada.html

在此示例中,文件缓存目录为“cache/”,存储的wiki页面命名为“Página …”,生成一个对应的“Página_…”。html文件。 这些文件将在用户访问wiki上的文章时创建;您可以使用rebuildFileCache.php 维护脚本一次性创建它们。

文件缓存倾向于积极缓存;缓存的页面没有设置到期日期,即使页面包含变量、扩展名和其他可变输出,也会无条件缓存。某些扩展禁用具有动态内容的页面的文件缓存。

考虑使用$wgUseGzip 代替或组合使用,以获得更有效的结果。

对于较大的站点,使用外部缓存(如squidvarnish)比启用文件缓存更好。

如果文件缓存似乎不工作,请确保Web服务器具有写入所选目录的权限。

限制

缓存文件的文件名由相应的页面标题决定。 根据页面标题中使用的语言,必须对文件名中的某些字符进行编码,以构成相应文件系统的有效文件名。 For languages like Arabic, Chinese and so on this may result in the following PHP warning:

PHP Warning:  file_put_contents(cache/......html.gz): failed to open stream: File name too long in includes/cache/FileCacheBase.php on line 171

這是一個已知限制。 参见工單T148684

分类和图像描述页不会从文件缓存中清除。 例如,从分类中添加或删除页面不会更新分类页面,导致未登录的用户无法看到分类页面中的更改。 这是一个已知的限制。 参见工單T26575

域和范围

缓存仅适用于以下用户:

仅对以下页面进行缓存:

  • 不是特殊页面。
  • 不是重定向。
  • 正在当前版本中查看,纯访问,无url参数

这涵盖了对wiki的大多数请求,但设置字节码和应用程序缓存来处理其余的请求仍然很重要。

驗證

缓存文件的修改时间与每次访问上设置为LocalSettings.php 的全局$wgCacheEpoch 时间戳进行比较。

如果文件至少与这两个文件一样新,则认为它是有效的,并直接发送给客户端。如果它较旧或不存在,将继续分析和渲染,并保存结果以供将来使用。

验证

通过将$wgCacheEpoch设置为当前时间或删除缓存中的所有文件,可以使整个缓存无效。

通过更新其page.page_touched字段,单个页面将失效,调用Title::invalidateCache()可以方便地完成。 这应该在文章创建、编辑保存、重命名以及链接文章的创建和删除(以便更新编辑链接)时完成。 编辑模板时发生的无效操作,例如,检查使用模板将缓存日期与page_touched进行比较的页面。

一些情况尚未得到妥善处理,可能包括:

  • 浏览器“重新加载”或“刷新”(只重新加载相同的缓存页面而不更新)
  • 来自扩展(如$1)的输出变量禁用这些页面的文件缓存,以避免过时数据。

即使在浏览器刷新时,那些不返回的数据也会返回过时的数据。

  • 某些长错误消息可以无限期缓存,就像它们是有效的页面内容一样;只有?action=purge将在存储后从文件缓存中删除这些文件。 最小输出大小阈值用于避免缓存大多数错误,如致命的PHP错误。

另请参阅:Manual:$wgInvalidateCacheOnLocalSettingsChange

過期

可能会有一些缓存页面过期的方法,特别是对于包含变量的页面(它是X日期,我们有X篇文章等)。

如果$parserOutput->getCacheTime()-1,则页面输出将禁用文件缓存。 没有设置到期时间的规定,因此所有页面的所有HTML都将永久缓存。 一个显式的?action=purge命令(或对页面的编辑)将重新生成该页面,但MediaWiki内部无缓存标志和浏览器刷新都不会删除过期的扩展输出,一旦它作为文件缓存页面的一部分存储。

刷新选项卡

可以添加一个选项卡来强制一个单独的页面无效并使用?action=purge使用清理页面缓存扩展进行清除。

壓縮

可选地,可以压缩缓存以节省空间和带宽。(这需要在PHP配置中启用zlib。)

$wgUseGzip = true;

如果启用压缩,缓存文件将保存为.html.gz。 在Accept-Encoding字段中宣传支持gzip的浏览器将直接获得gzip版本;对于那些没有这样做的浏览器,我们会立即解压缩数据,并将明文发送给它们。

将发送一个"Vary: User-agent"标头,告诉代理缓存要更加小心地向谁重新发送数据。 (“Vary: Accept-encoding”更合适,但Internet Explorer拒绝缓存如此标记的页面。)

警告 警告: 如果已启用输出缓冲以gzip内容(通过ob_gzhandlerzlib.output_compression),请不要启用$wgUseGzip 。这样做将导致向用户显示胡言乱语。

紧急回退

如果wiki无法与数据库服务器联系,它将尝试显示请求的任何页面的缓存版本,无论该页面是否为当前页面,并在其中添加“database is down”消息。

這有一些限制:

  • 特殊页面没有任何覆盖,只有一条警告信息
  • 重定向页面未缓存,因此单击指向重定向的链接不会到达最终目标
  • 由于MediaWiki检查DB以查看标题是否具有有效的跨wiki前缀,标题中带有冒号的页面(有效命名空间除外)仍可能失败。只有当页面前缀没有跨wiki缓存条目(请参见$wgInterwikiExpiry )或$wgMainCacheType 回退到(或设置为)DB_cache时,才会出现这种情况。
  • 尝试使用非访问操作会导致纯页面视图,这可能会令人困惑
  • MySQL连接超时可能会有问题,这会导致放弃前花费很长时间,特别是如果使用持久连接并且数据库稍后失效。调整php.ini中的mysql.connect_timeout(设置为3或更多)以解决。编辑Web服务器的php.ini而不是命令行的php.ini。


直接提供缓存页面

默认情况下,MediaWiki使用php传递缓存页面。下面是我们如何使用Web服务器配置技巧直接提供缓存文件,而根本不调用MediaWiki或PHP。

首先,设置$wgFileCacheDepth = 0;。然后我们添加重写规则。见下文。

Apache

已发现以下mod_rewrite规则在运行Apache 2.2的共享Web主机上的.htaccess文件中有效:

RewriteBase /
# If a cached page exists under /w/html_cache, do an internal redirect to it:
RewriteCond %{HTTP_COOKIE} !UserID=
RewriteCond %{QUERY_STRING} !.
RewriteCond %{DOCUMENT_ROOT}/w/html_cache/$1.html -s
RewriteRule ^wiki/(.+)$ /w/html_cache/$1.html [B,L,NS]

然而,对于标题包含标点符号或非ASCII字符的页面,此重写规则无法正常工作。 一个整洁的解决方案是使用RewriteMap,但.htaccess上下文不支持这一点。 相反,通过直接从原始请求行提取URL转义标题,可以使用以下技巧处理非ASCII标题:

RewriteBase /
# If a cached page exists under /w/html_cache, do an internal redirect to it: 
RewriteCond %{HTTP_COOKIE} !UserID=
RewriteCond %{QUERY_STRING} !.
ReWriteCond %{THE_REQUEST} ^GET\x20/wiki/([^\x20/]+)\x20HTTP
RewriteCond %{DOCUMENT_ROOT}/w/html_cache/%1.html -s
RewriteRule ^wiki/(.+)$ /w/html_cache/%1.html [B,L,NS]

The previous rewrite rules will handle requests of the form

https://site/wiki/Page_Name

To handle requests where the Page_Name is in the QUERY_STRING like

https://site/w/index.php?title=Page_Name

the following works:

RewriteCond %{HTTP_COOKIE} !UserID=
RewriteCond %{QUERY_STRING} ^title=([^&]+)$
RewriteCond %{DOCUMENT_ROOT}/images/cache/ns0\%3A%1.html -s
RewriteRule ^ /images/cache/ns0\%253A%1.html? [B,L,NS]

这仍然与包含句点、斜线或其他标点符号的标题不匹配,文件缓存会转义这些标点符号,但浏览器不会(反之亦然)。 还应确保发送适当的Vary标头:

Header append Vary Cookie

还要注意,由于这个重定向技巧完全绕过了MediaWiki,所以它不会尊重$wgCacheEpoch 。 您可能需要根据需要手动清除或重建缓存。

Nginx

由于nginx配置语言非常有限(例如,它不允许嵌套if语句),因此它需要ngx_lua模块

以下conf应该集成在服务器块中,它假设:

  • 您正在使用的url类似于example.com/Page;
  • 缓存文件夹位于MediaWiki文件夹中(默认);
  • 你已经在最终的location块中将.php文件代理到php-fpm(或其他文件)。

并且這有一些限制:

  • 与Apache解决方案一样,您必须运行cron作业或在缓存文件更改时手动重建缓存文件;
  • 标题包含非ASCII字符的页面是通过PHP提供的(无论如何对用户来说应该是透明的)。

根据需要更改路径。

 location ~ /cache/(.*) {
     internal;
 }
 
 location / {
     default_type 'text/html';
     rewrite_by_lua '
         local cookie = ngx.req.get_headers()["Cookie"] or ""
         if string.match(cookie, "UserID") then  -- if we are logged in...
             ngx.exec("@rewrite")
         else
             local page = string.sub(ngx.var.request_uri, 2, -1)  -- get the page name without the leading slash
             local filename = page .. ".html"
             local f = io.open("/var/www/w/cache/" .. filename, "r")
             if f ~= nil then  -- if the file exists, close it and serve it directly
                 io.close(f)
                 ngx.header["x-wiki-cache"] = "via nginx"  -- headers to help you debug
                 ngx.exec("/cache/" .. filename)
             else
                 ngx.header["x-wiki-cache"] = "via mediawiki"
                 ngx.exec("@rewrite")
             end
         end
     ';
 }
  
 location @rewrite {
     rewrite ^/([^?]*)(?:\?(.*))? /index.php?title=$1&$2 last;
 }

代码维护

參見