カテゴリー
コンピュータ

MediaWikiでVarnishを使う

MediaWikiでVarnishでキャッシュヒット率を上げるために変更した点など… おかしいぞなどあればコメントください

Manual:Varnish cachingのVCLをコピーしたら「おまかせ表示」までキャッシュしてえらい目にあった😭

環境

  • Varnish 6.3 – VCL 4.1
  • MediaWiki 1.37

構成例

インターネット <—>

Varnish
203.0.113.10:80

<—>

MediaWiki
203.0.113.1:80

  • IP:203.0.113.1 – MediaWiki(Nginx)サーバ
  • IP:203.0.113.10 – Varnishサーバ

(IPアドレスは例示用です)

MediaWiki

MediaWikiは標準で更新時にVarnishのキャッシュをパージ(削除)する機能がついているので設定するだけで使用することができます。

$wgUseCdn = true;
$wgCdnServers = [ '203.0.113.10:80' ];
$wgCdnServersNoPurge = ['203.0.113.10' ]

PURGEリクエスト送る必要のあるIPアドレスを$wgCdnServers に指定 、Portを指定している場合 $wgCdnServersNoPurge にもIPアドレスの指定が必要です。 (※X-Forwarded-Forが適切に扱われず編集者のIPアドレスすべて同じになります)

⚓ T132538 isConfiguredProxy not recognizing $wgSquidServers with port

その他設定

$wgCdnMaxAge = 	18000; //5 hour
$wgResourceLoaderMaxage = [
	'versioned' => 30 * 24 * 60 * 60, // 30 days
	'unversioned' => 5 * 60 // 5 minutes
];
$wgInternalServer = 'http://example.com';

$wgCdnMaxAge 記事ページの s-maxage 日付を扱うwikiは短めにしたほうが良いかも

$wgResourceLoaderMaxage ResourceLoader関連

$wgInternalServer パージ時に使われるサーバURL $wgServerが https://~と指定していたので http://~ になるアドレスを書いた

Varnish

backend default にMediaWikiが動作しているサーバIP・Port、acl purge にも同じIPアドレスを指定します

#
# VCL file for Varnish.
#
vcl 4.1;
backend default {
    .host = "203.0.113.1";
    .port = "80";
}
# access control list for "purge": open to only localhost and other local nodes
acl purge {
    "203.0.113.1";
}
# vcl_recv is called whenever a request is received 
sub vcl_recv {
    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);
        }
    }

    if (req.method == "PRI") {
    /* This will never happen in properly formed traffic (see: RFC7540) */
    return (synth(405));
    }
    
    if (!req.http.host &&
      req.esi_level == 0 &&
      req.proto ~ "^(?i)HTTP/1.1") {
    /* In HTTP/1.1, Host is required. */
    return (synth(400));
    }
    

    
    if (req.method != "GET" &&
      req.method != "HEAD" &&
      req.method != "PUT" &&
      req.method != "POST" &&
      req.method != "TRACE" &&
      req.method != "OPTIONS" &&
      req.method != "DELETE" &&
      req.method != "PATCH") {
    /* Non-RFC2616 or CONNECT which is weird. */
    return (pipe);
    }
    if (req.method != "GET" && req.method != "HEAD") {
    /* We only deal with GET and HEAD by default */
        return (pass);
    }
    
 
    # 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;
      }
    }
    
    # 
    # Static-File
    # 
    if (req.url ~ "^(\/w\/load.php|\/w\/images|\/w\/resources)") {
        unset req.http.Cookie;
        return(hash);
    }
    
    # 
    # Authorization Cookie session|Token
    #
    if (req.http.Authorization || req.http.Cookie ~ "([sS]ession|Token)") {
        return (pass);
    } /* Not cacheable by default */
    # 
    # Remove  _* cookies. Google,Cloudflare...
    # 
    set req.http.Cookie = ";" + req.http.Cookie;
    set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_[a-zA-Z1-9_]+)=[^;]*", "");;
    # Remove a ";" prefix, if present.
    set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", "");
    return (hash);
}
sub vcl_pipe {
    # By default Connection: close is set on all piped requests, to stop
    # connection reuse from sending future requests directly to the
    # (potentially) wrong backend. If you do want this to happen, you can undo
    # it here.
    unset bereq.http.connection;
}
sub vcl_backend_response {
    # Serve stale content for 2 minutes after object expiration
    # Perform asynchronous revalidation while stale content is served
    set beresp.grace = 120s;
}

説明

変更した点や解説など

X-Forwarded-For

Varnish 6 からは X-Forwarded-ForはVarnishが自動で追加します

Upgrading to Varnish 6.0 — Varnish version 6.2.3 documentation

Authorization Cookie session|Token

Cookieにsession、Tokenが含まれる場合キャッシュしない。

Static-File

Cookie を送る必要のない静的ファイルはCookieを消しキャッシュヒット率を上げます(wiki構成に応じて変更してください)

ディレクトリ説明
/w/load.phpResourceLoader
/w/imagesアップロードされた画像
/w/skins/Vector/resources/Vectorスキンに使われるアイコンなど
/w/resources/組み込みアイコン (poweredby_mediawiki、編集アイコンなど)
Cookie 無視してもいいファイル

Remove _* cookies

Google AnalyticsなどのCookieを削除 

  • _ga Google Analytics
  • _ga_~ Google Analytics
  • _gads Google AdSense
  • __cf~ CloudFlare

{wikiID}mwuser-sessionIdはMediaWiki JS がセットするので削除して良いかも

beresp.grace

grace 非同期でキャッシュを更新する期間を設定

Varnish Grace Modeで非同期にキャッシュを更新する – LCL Engineers’ Blog

参考リンク

コメントを残す