Manual:File cache/ja

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" と等しい)

これにより、ウィキの各ページのレンダリングされた HTML ウェブページは、ハードディスク上の個別のファイルに保存されることになります。匿名利用者からのリクエストには、ページを再レンダリングするのではなく、ディスクに保存された HTML 版を送信することで対応します。これは時間の節約になります。

生成したHTMLウェブテキストはディスク上の$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/ ディレクトリにキャッシュされ、保存されたウィキのページにはPágina ... という一連の名称が与えられ1件ずつPágina_....htmlを取得します。 これらのファイルは、利用者がウィキ上のファイルにアクセスするたびに生成されるもので、rebuildFileCache.php メンテナンス スクリプトを使用すると一括して生成できます。

ファイルキャッシュは積極的にキャッシュする傾向があり、キャッシュされたページには有効期限が設定されておらず、ページには変数や拡張子などの変更可能な出力が含まれていても無条件でキャッシュされます。拡張機能の中には、動的なコンテンツを含むページに対してファイルキャッシュを無効にするものもあります。

より効果的な結果を得るために、$wgUseGzip を代わりに使用するか、組み合わせて使用することを検討してください。

規模が大きなサイトでは、ファイルキャッシュにSquidあるいはVarnish等、外部のキャッシュの利用が望まれます。

ファイルキャッシュが機能していないように見える場合は、ウェブサーバーが選択したディレクトリに書き込む権限を持っていることを確認してください。

制限

キャッシュファイルのファイル名は、そのページのタイトルによって決定されます。 ページタイトルに使用されている言語によっては、ファイル名に含まれる一部の文字をエンコードして、該当するファイルシステムで有効なファイル名を構成する必要があります。 アラビア語や中国語などの言語では、以下のようなPHPの警告が表示されることがあります。

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> を参照してください。

ドメインと範囲

キャッシュ処理が可能なユーザーの対象:

  • ログインしていない。
  • user_newtalkのフラグを無効にしてある。

キャッシュは、以下のようなページに対してのみ行われます。

  • 特別ページでないこと。
  • リダイレクトでないこと。
  • 現在のバージョン、プレーンビュー、URLパラメータなしで表示されていること。

これでウィキに対する要求の大部分をカバーできるものの、その他の項目の処理にはバイトコードとソフトウェアのキャッシュ処理の設定が重要です。

検証

キャッシュしたファイルの変更時刻は、各ビューの LocalSettings.php で設定されたグローバルな $wgCacheEpoch タイムスタンプと比較されます。

少なくともこの両方と同じくらい新しいファイルであれば、有効であると判断され、直接クライアントに送信されます。それより古いか存在しない場合は、パースとレンダリングが続行され、結果は将来の使用のために保存されます。

無効化

$wgCacheEpoch を現在時刻に設定するか、キャッシュのファイルをすべて削除すると、全キャッシュを無効にできます。

個々のページの無効化には page.page_touched フィールドの更新を行い、Title::invalidateCache() を呼び出すと簡便に実行できます。 これは、記事の作成、編集の保存、名前の変更、リンクされた記事の作成と削除(編集リンクを更新するため)の際に行われるべきものです。 例えばテンプレートの編集による無効化の操作は、page_touched とキャッシュ日付を照合するテンプレートを採用するページを確認します。

事例によっては以下のように、まだ適切に処理されていません。

  • ブラウザの「再読み込み」または「更新」(キャッシュされた同じページを更新せずに再読み込みする)
  • Extension:DynamicPageList などの拡張機能からの出力変数は、古いデータを避けるために、それらのページのファイルキャッシュを無効にします。 そうしないと、ブラウザの更新時に古いデータが返されます。

特定の長いエラーメッセージは、有効なページコンテンツであるかのように無期限にキャッシュされることがあります。?action=purgeだけが、一度保存されたファイルキャッシュからこれらを削除します。 最小出力サイズのしきい値を使用し、致命的な PHP エラー等、ほとんどのエラーをキャッシュしないようにしています。

関連項目: Manual:$wgInvalidateCacheOnLocalSettingsChange

有効期限

キャッシュページの有効期限、特に変数(今日はX日、X個の記事がある、など)を含むページについては、おそらく何らかの方法があるはずです。

varが-1の場合、ページの出力に対してファイルキャッシュは無効になります。 有効期限を設定する規定がないため、すべてのページのHTMLが永久にキャッシュされます。 明示的な ?action=purge コマンド (またはページの編集) によって特定のページは再生成されますが、有効期限切れの拡張機能の出力がファイルをキャッシュしたページの一部として記録されると、MediaWiki 内部の no-cache フラグまたはブラウザーの更新でもそれを削除しません。

更新タブ

Purge page extensionを当てて?action=purgeを実行すると、特定の個別のページを強制的に無効化して更新するタブを追加できます。

圧縮

選択肢として、キャッシュを圧縮して空間と帯域を節約できます。(前提としてPHP configにおいて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> (ob_gzhandler または zlib.output_compression を使って) コンテンツを gzip で圧縮する出力バッファリングを有効にしている場合は、$wgUseGzip を有効にしないでください。これをすると、利用者におかしな文章が表示されることになります。

緊急時のフォールバック

ウィキがデータベースサーバにコンタクトできない場合、リクエストされたページが最新かどうかに関わらず、「database is down」メッセージとともにキャッシュされたバージョンを表示しようとします。

これにはいくつかの限界があります。

  • 特別ページには何も表示されず、警告メッセージが表示されるだけです。
  • リダイレクトページはキャッシュされないので、リダイレクト先のリンクをクリックしても最終的なページには到達しない
  • タイトルにコロン(:)があるページ(有効な名前空間のため以外)はMediaWikiがタイトルに有効なインターウィキプレフィックスがあるかどうかDBをチェックするのに失敗するかもしれません。これは、ページのプレフィックスに対応するインターウィキキャッシュのエントリが存在しないか($wgInterwikiExpiry を参照)、$wgMainCacheType DB_CACHEにフォールバックしている(あるいは設定されている)場合にのみ起こります。
  • 閲覧以外の操作を使用すると、プレーンなページ表示になり、混乱する可能性があります
  • MySQL 接続のタイムアウトに問題があると、特に永続的な接続を使用していてデータベースが後で終了する場合、処理中止までに容認できないほど長い時間がかかってしまいます。php.ini で mysql.connect_timeout を調整し (3 以上に設定) この問題に対処します。調整する 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コンテキストではサポートされていません。 非ASCIIタイトルの処理の代替策として次のトリックを使用すると、URLをエスケープした題名を直接、生の要求行から取り出すことができます。

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

もう1点、このリダイレクトのトリックでは MediaWiki を完全に回避するため、$wgCacheEpoch を反映しません。 そこで必要に応じて、手動でキャッシュを再構成する場面が生じることがあります。

Nginx

設定言語がかなり限定される(例えばif文は入れ子にできない)nginxは、必ずngx_lua moduleと組んで使います。

前提条件を確認して下記の設定をサーバブロックに組み込んでください:

  • example.com/Page のような展開したURLを使用している。
  • キャッシュ フォルダーは (既定の) MediaWiki フォルダー内にある。
  • 既に最後のロケーション ブロック内で *.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;
 }

コード管理

関連項目