Manual:File cache/zh

From Linux Web Expert

The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

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

這是一個已知限制。 参见<translate> task <tvar name=1>T148684</tvar></translate>

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

域和范围

缓存仅适用于以下用户:

仅对以下页面进行缓存:

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

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

驗證

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

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

验证

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

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

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

  • 浏览器“重新加载”或“刷新”(只重新加载相同的缓存页面而不更新)
  • 来自扩展(如Extension:DynamicPageList )的输出变量禁用这些页面的文件缓存,以避免过时数据。 即使在浏览器刷新时,那些不返回的数据也会返回过时的数据。
  • 某些长错误消息可以无限期缓存,就像它们是有效的页面内容一样;只有?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拒绝缓存如此标记的页面。)

File:OOjs UI icon notice-destructive.svg <translate> Warning:</translate> 如果已启用输出缓冲以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。
  • 如果$wgStatsMethod 设置为cache,而$wgMainCacheType回退到(或设置为)DB_CACHE,则回退可能失败


直接提供缓存页面

默认情况下,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;
 }

代码维护

參見