序章

バックグラウンド

Drupal は、最も人気のある無料のオープンソースコンテンツ管理システムの1つです。

基盤となるデータベースを使用してコンテンツページ、ニュースアイテム、コメント、ブログ投稿などのデータを保存および取得するため、Drupalは単一のページビューを提供するためにかなりの処理能力を必要とします。 各ページの印象には、PHPインタープリターの起動、すべてのDrupal要素の処理、データベースへのアクセスによる情報の取得、ビジュアルレイアウトの準備、およびユーザーへの準備が整ったコンテンツの提供が含まれます。

この集中的なプロセスにより、Webサイトを同時に表示する人の増加に対処することが困難になります。 各訪問者は、無視できない量の処理能力を提供する必要があるため、サーバーリソースがすぐにボトルネックになる可能性があります。

成長に対応し、パフォーマンスの問題に対処する方法はたくさんありますが、そのほとんどはスケーリングの方法と見なすことができます。 ソフトウェアの観点からのスケーリングは、同時訪問者数の増加など、増加した負荷に対応するシステムの機能と見なされます。

Varnish は、ボトルネックに役立つソフトウェアを追加することにより、ソフトウェアレベルでのスケーリングに役立ちます。

この記事はUbuntu14.04 でテストされましたが、 Debian7でのマイナーなパス変更で動作するはずです。 マイナーな変更を加えれば、他のディストリビューションでも機能する可能性があります。

ワニスキャッシュ

Varnish はキャッシュです。つまり、その役割は、コンテンツに最初にアクセスしたときにWebアプリケーションがユーザーに提供するものを保存して記憶することです。 その後、Webアプリケーションに再度要求することなく、後続の要求に対して同じコンテンツを再度提供できます。

Varnishは非常に高速で、 Apache よりもはるかに優れたトラフィック処理を行うため、画像、スクリプト、スタイルシートなどの静的コンテンツを提供するために使用できます。 準静的コンテンツをキャッシュするためにも使用できます。 つまり、アプリケーションによって動的に生成される(データベースを使用し、準備にかなりの時間がかかる)コンテンツですが、一定期間変更されないため、コンテンツはキャッシュに適しています。

たとえば、Webサイトの記事が公開されても、更新されることはめったにありません。 その場合、Drupalのすべての処理ビットと断片を使用して、要求されるたびに同じ記事を計算して表示する必要はまったくありません。 Drupalにまったく連絡せずに、Varnishが同じページを再度提供することを覚えていればまったく問題ありません。 これにより、Varnishは、同じコンテンツを一度に10人、100人、さらには1000人に簡単に提供できます。キャッシュされたページを提供するために必要な処理能力はごくわずかだからです。

Varnish を使用するほとんどのシナリオでは、ほとんどすべてのWebサイトが信じられないほど高速になります。 また、突然の関心の急上昇(たとえば、非常に人気のある記事が公開された場合)への対処も容易になります。 これはすべて、コンテンツをより速く、より確実に配信するより幸せな訪問者につながります。

前提条件

この記事では、LAMPでDrupalベースのWebサイトがすでに稼働していることを前提としています。 要件は次のとおりです。

  • Ubuntu14.04またはDebian7 ドロップレット(Ubuntu 14.04でテスト済み)
  • sudoユーザー
  • ランプ
  • Drupal

ステップ1—Apacheを再構成する

デフォルトでは、Apacheはポート80でリッスンします。 これにより、Apacheはhttp://example.comのブラウザURLリクエストのようなWebリクエストを処理できます。 Varnish を使用するには、代わりにそれらの要求を処理できる必要があります。 まず、Apacheにポート80でのリクエストを処理しないように指示する必要があります。

Apacheがリッスンするポートの変更

Apache がデフォルトでリッスンするポートは、DebianUbuntuの両方にあるports.confというファイルに設定されています。 /etc/apache2で。

ファイルを編集します。

sudo nano /etc/apache2/ports.conf

これにより、 nano テキストエディタが実行され、そのファイルのデフォルトの内容が表示されます。これは次のようになります。 NameVirtualHostおよびListen行を更新して、ポート81を使用します。

# If you just change the port or add more ports here, you will likely also
# have to change the VirtualHost statement in
# /etc/apache2/sites-enabled/000-default
# This is also true if you have upgraded from before 2.2.9-3 (i.e. from
# Debian etch). See /usr/share/doc/apache2.2-common/NEWS.Debian.gz and
# README.Debian.gz

NameVirtualHost *:81
Listen 81

<IfModule mod_ssl.c>
    # If you add NameVirtualHost *:443 here, you will also have to change
    # the VirtualHost statement in /etc/apache2/sites-available/default-ssl
    # to <VirtualHost *:443>
    # Server Name Indication for SSL named virtual hosts is currently not
    # supported by MSIE on Windows XP.
    Listen 443
</IfModule>

CTRL + x y Enterの順に押してファイルを保存しましょう。

仮想ホストのポートの変更

デフォルトでは、 Apache の新規インストールでは、/etc/apache2/sites-enabled/000-defaultにある構成ファイルで1つの仮想ホストが指定されています。 複数の仮想ホストを構成している場合は、それらのすべてを変更する必要があります。

デフォルトのApache仮想ホストの設定を変更するには、次のように入力します。

sudo nano /etc/apache2/sites-enabled/000-default.conf

ファイルの内容は、次のような行で始まります。

<VirtualHost *:80>
        ServerAdmin webmaster@localhost

以前と同様に、番号を80から81に変更する必要があります。

<VirtualHost *:81>
        ServerAdmin webmaster@localhost

CTRL-x y Enterの順に使用してファイルを保存します。

Apache構成の再ロード

これらの変更後、Apache構成を再ロードする必要があります。

sudo service apache2 reload

これで、Apacheは、以前のように 80 ではなく、新しいポート81で着信要求を受け入れます。

ブラウザでウェブサイトを開くことで確認できます。ポートを指定しないと開くことができませんが( http://example.com など)、アドレスに新しいポートを追加すると正しく表示されます(たとえば http://example.com:81 )。

これで、 Varnish をインストールして構成し、サイトを高速化する準備が整いました。

ステップ2—ワニスのインストール

DebianとUbuntuの両方にVarnishのシステムパッケージがありますが、Varnishの作者によって作成されたビルド済みパッケージを使用することをお勧めします。 これにより、Varnishが最新の状態になりますが、これはシステムパッケージには当てはまりません。

まず、 apt-transport-https パッケージがインストールされていることを確認します。これにより、システムは安全な接続を介してパッケージをインストールできます。

sudo apt-get install apt-transport-https

これにより、必要なパッケージがインストールされるか、すでにインストールされていることがわかります。

インストールされたパッケージの信頼性を検証するには、Varnishパッケージサーバーの公開鍵をインストールする必要があります。 まず、rootに切り替えます。

sudo su

キーを追加します。

curl https://repo.varnish-cache.org/ubuntu/GPG-key.txt | apt-key add -

Debian の場合:

echo "deb https://repo.varnish-cache.org/debian/ wheezy varnish-4.0" >> /etc/apt/sources.list.d/varnish-cache.list

Ubuntu の場合:

echo "deb https://repo.varnish-cache.org/ubuntu/ trusty varnish-4.0" >> /etc/apt/sources.list.d/varnish-cache.list

これで、sudoユーザーに戻ることができます。

システムを更新します。

sudo apt-get update

ワニスをインストールします。

sudo apt-get install varnish

これにより、Varnishがインストールおよび実行されます。

ステップ3—ポート80でワニスをリッスンさせる

デフォルトでは、Varnishはポート6081でリッスンします。 代わりに、Varnishをポート 80 でリッスンさせ、 Apache が以前に行ったように、Webユーザーからのすべての着信要求を受け取ります。

以下を使用してVarnish構成ファイルを開きます。

sudo nano /etc/default/varnish

以下に示すコメントのないセクションを見つけます。

. . .

## Alternative 2, Configuration with VCL
#
# Listen on port 6081, administration on localhost:6082, and forward to
# one content server selected by the vcl file, based on the request.
# Use a 256MB memory based cache.
#
DAEMON_OPTS="-a :6081 \
             -T localhost:6082 \
             -f /etc/varnish/default.vcl \
             -S /etc/varnish/secret \
             -s malloc,256m"
             
. . .

DAEMON_OPTS = “-a:行を更新して、ポート 80 を使用します(\も保持することを忘れないでください)。

. . .

DAEMON_OPTS="-a :80 \
             -T localhost:6082 \
             -f /etc/varnish/default.vcl \
             -S /etc/varnish/secret \
             -s malloc,256m"

. . .

CTRL-xyに続いて、Enterを使用してファイルを保存します。

Varnish を再起動して、変更を有効にします。

sudo service varnish restart

次のようなメッセージがエラーなしで表示されるはずです。

[ ok ] Stopping HTTP accelerator: varnishd.
[ ok ] Starting HTTP accelerator: varnishd.

次に、ブラウザでWebサイトを確認します。 以前に利用可能だったDrupalサイトの代わりに、次のようなエラーメッセージが表示された白いページが表示されます。

Error 503 Backend fetch failed

Backend fetch failed

Guru Meditation:
XID: 131081

Varnish cache server

つまり、Varnishは着信接続を受け入れるように適切に構成されていますが、Drupalサイトにサービスを提供するためにまだ利用できません。 次の手順で、以前のDrupalサイトをオンラインに戻すために構成を変更します。

ワニスのしくみ

ワニスをしっかりと理解するための優れたリソースは、公式のワニスブックですが、ここではワニスの仕組みに関するいくつかの基本的な事実について説明します。

今すぐインストールを終了して後で詳しく知りたい場合は、次のステップにスキップすることもできます。 ただし、Varnishがどのように機能するかを学ぶと、次のステップをより深く理解できるようになります。

VCL言語

ワニスの構成は、 VCL (ワニス構成言語)と呼ばれる言語で記述されています。 これは、Varnish自体によってネイティブCコードにコンパイルされる単純なプログラミング言語です。

構成は、メソッドで構成され、着信Web要求を処理するさまざまな瞬間に実行され、残りの構成コンテンツも含まれます。

一部の命令は、ブラウザからリクエストを受信したときに、リクエストが処理される前にVarnishによって実行されます。これにより、リクエストを実際のアプリケーションに転送するか、キャッシュされたコンテンツを提供するかが指示されます。 これらの手順では、着信要求を操作したり、その内容を変更したり、要求(URL、ファイル名、ヘッダー、またはCookie)に基づいて決定を下したりすることができます。

その他の命令は、Varnishが実際のアプリケーション(この場合はDrupal Webサイト)からコンテンツを取得することを決定したときに実行されます。 これらの命令は、アプリケーションから受け取ったコンテンツを操作するために使用できます。

さらに他の命令は、Varnishがキャッシュされたコンテンツをアプリケーションから新しく取得せずに提供するときに実行されます。

VCL を使用すると、多くの要因に基づいてさまざまなキャッシュ決定を行う複雑なロジックを構築できます。 非常に単純な一連の命令を作成することも可能です。

Varnishには、 all の適切なデフォルトの実装が付属しており、必要に応じてメソッドを変更できます。 つまり、構成で some メソッドのみを指定でき、それでも some 命令のみを指定でき、残りはデフォルトに依存します。 これにより、基本的なワニス機能を非常に簡単に使用できると同時に、カスタム命令を追加するときに非常に複雑な構成を作成することができます。

何がキャッシュされ、何がキャッシュされないのですか?

おそらく、Varnishまたはその他のキャッシュメカニズムを構成する上で最も難しいのは、いつおよびをキャッシュするかを決定することです。 ほとんどの問題は、キャッシュが多すぎるか不十分であるという不適切な決定に起因します。

通常のDrupalのインストールでは、これにより2つの異なる問題シナリオが発生する可能性があります。

1つ目は、十分なページがキャッシュされていない場合です。これにより、Varnishはほとんど不要になります。 ほとんどのページは毎回Drupalアプリケーションから直接フェッチされるため、速度はまったく向上しません。 これはパフォーマンスの問題には役立ちませんが、何も壊すことはありません。

2つ目は、キャッシュされるページが多すぎる場合です。 この場合、管理パネルにまったくログインできない可能性があります。 匿名ユーザーとログインユーザーに異なるコンテンツが提供されると、訪問者は古い、無効なコンテンツ、または混同されたコンテンツを取得する可能性があります。 このシナリオでは、ワニスなしで正常に機能したものを壊すことができます。

Varnish がコンテンツをキャッシュするかどうかを決定するのに役立つ、いくつかの一般的な要因を調べてみましょう。

ワニスはすべてをキャッシュします

デフォルトのシナリオでは、基本的な前提は、Varnishがすべてをキャッシュすることです。 ワニスのキャッシュは排他的であり、包括的ではありません。つまり、特にルールを作成しない限り、すべてがキャッシュされます。

リクエスト方法

requestメソッドは、リクエストの基本的な定義です。 ワニスはデフォルトでのみGETおよびHEADリクエストをキャッシュし、決して POST PUTなどの他のものをキャッシュしません、およびDELETE。 これにより、データにいくつかの変更を加えることを目的としたリクエストが、キャッシュされることなくアプリケーションにそのまま届くようになります。

承認

デフォルトでは、パスワードで保護されたページへのリクエストはまったくキャッシュされません。 これは、HTTP基本認証を使用して保護されたページにのみ当てはまります。 Varnishは、Drupalログインページなどのアプリケーション固有のメカニズムを認識していません。 ログインページがキャッシュされないように、独自のルールを追加する必要があります。

キャッシュヘッダー

Webアプリケーションは、独自のキャッシュ情報をヘッダーで返す場合があります。 Varnishはこれらのヘッダーを考慮に入れるため、DrupalなどのWebアプリケーションがVarnishに応答をキャッシュしないように指示すると、 VCL ファイルで別の動作をプログラムしない限り、まさにそれが発生します。 Drupalは独自のキャッシュ情報を送信するため、これはさらに重要になります。

クッキー

Cookieは、Webアプリケーションでキャッシュを決定する上でおそらく最も重要で最も難しい部分です。

デフォルトでは、リクエストまたは応答Cookieが設定されている場合、ページはキャッシュされません。 たとえば、ログインしているユーザーはセッションCookieによって識別されるため、これは賢明な決定です。 Cookieを含むページがキャッシュされた場合、ログインしているすべてのユーザーが同じコンテンツを取得し、アプリケーションはユーザーを識別できなくなります。 ただし、Cookieの使用が広まっているため、これも最大の問題の原因の1つです。 多くの場合、 Google Analytics トークンなどの無害なCookieがリクエストに含まれています。これらのトークンは、アプリケーションではまったく使用されませんが、コンテンツもキャッシュできなくなります。 どのCookieがキャッシュを禁止し、どれを無視するかを慎重に決定しないと、今日のWebアプリケーションでは、非常に多くのCookieが浮かんでいるため、キャッシュがほとんどなくなります。

VarnishのDrupal固有の構成のほとんどのフラグメントは、適切なCookie処理を処理して、不要なCookieを削除し、キャッシュを許可しますが、たとえば、管理ページの機能を維持するために必要なCookieを保持します。

ステップ4—Drupal用のワニスの構成

Varnishを使用したキャッシングがどのように機能するかについての基本的な理解ができたら、Drupalサイトで機能するようにVarnishを構成することができます。

VarnishVCL構成ファイルを開きましょう。

sudo nano /etc/varnish/default.vcl

デフォルトの内容では、すべてのVarnishメソッドが空であることが示されています。これは、デフォルトが使用されていることを意味します。

必要なキャッシュポリシーを実現するために、独自の構成手順を追加できます。

最初のブロックは、バックエンドWebサーバー(この場合は ApacheDrupalインストール)への接続方法をVarnishに指示します。 Apacheの構成に使用したポート81を反映するようにコードを変更します。

. . .

# Default backend definition. Set this to point to your content server.
backend default {
    .host = "127.0.0.1";
    .port = "81";
}

. . .

次に、空のプレースホルダーメソッドvcl_recvを見つけます。

. . .

sub vcl_recv {
    # Happens before we check if we have this in cache already.
    #
    # Typically you clean up the request here, removing cookies you don't need,
    # rewriting the request, etc.
}

. . .

このメソッドのコードは、 VarnishDrupalサイトに接続する前に実行されます。 これは、ブラウザからのCookieを削除し、特定のアドレスに対してキャッシュを強制する(またはしない)ことができ、最初のキャッシュ決定を行うことができる場所です。 以下を実現するいくつかのルールを追加します。

  1. Drupalに障害が発生した場合に、Varnishが古い(古い)キャッシュコンテンツを提供できるようにします。 Drupalが応答しなくても、サイトを部分的に利用できるようにします
  2. 管理ページがまったくキャッシュされていないことを確認し、Varnishに特定のURLのキャッシュをスキップさせます
  3. 静的ファイル(画像、スクリプト、スタイルシート)のキャッシュを確保する
  4. ユーザーログイン機能を含め、Drupalが正しく機能するために必要ないくつかのCookie以外のすべてのCookieを削除します

これを実現するために、デフォルトのブロックを次のブロックに置き換えましょう。 で始まる行はコメントであり、Varnishでは考慮されませんが、構成ファイルを理解しやすくするためにここにあります。 このブロック全体は新しく、そのまま貼り付けることができます。

. . .

sub vcl_recv {

    # Return (pass) instructs Varnish not to cache the request
    # when the condition is met.
    
    ## ADMIN PAGES ##
    
    # Here we filter out all URLs containing Drupal administrative sections
    if (req.url ~ "^/status\.php$" ||
        req.url ~ "^/update\.php$" ||
        req.url ~ "^/admin$" ||
        req.url ~ "^/admin/.*$" ||
        req.url ~ "^/user$" ||
        req.url ~ "^/user/.*$" ||
        req.url ~ "^/flag/.*$" ||
        req.url ~ "^.*/ajax/.*$" ||
        req.url ~ "^.*/ahah/.*$") {
           return (pass);
    }
	
	
	## BACKUP AND MIGRATE MODULE ##
	
    # Backup and Migrate is a very popular Drupal module that needs to be excluded
    # It won't work with Varnish
    if (req.url ~ "^/admin/content/backup_migrate/export") {
        return (pipe);
    }
	
	## COOKIES ##
	
    # Remove cookies for stylesheets, scripts, and images used throughout the site.
    # Removing cookies will allow Varnish to cache those files.
    if (req.url ~ "(?i)\.(css|js|jpg|jpeg|gif|png|ico)(\?.*)?$") {
        unset req.http.Cookie;
    }

    # Remove all cookies that are not necessary for Drupal to work properly.
    # Since it would be cumbersome to REMOVE certain cookies, we specify
    # which ones are of interest to us, and remove all others. In this particular
    # case we leave SESS, SSESS and NO_CACHE cookies used by Drupal's administrative
    # interface. Cookies in cookie header are delimited with ";", so when there are
    # many cookies, the header looks like "Cookie1=value1; Cookie2=value2; Cookie3..." 
    # and so on. That allows us to work with ";" to split cookies into individual
    # ones.
    #
    # The method for filtering unnecessary cookies has been adopted from:
    # https://fourkitchens.atlassian.net/wiki/display/TECH/Configure+Varnish+3+for+Drupal+7
    if (req.http.Cookie) {
        # 1. We add ; to the beginning of cookie header
        set req.http.Cookie = ";" + req.http.Cookie;
        # 2. We remove spaces following each occurence of ";". After this operation
        # all cookies are delimited with no spaces.
        set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
        # 3. We replace ";" INTO "; " (adding the space we have previously removed) in cookies
        # named SESS..., SSESS... and NO_CACHE. After this operation those cookies will be 
        # easy to differentiate from the others, because those will be the only one with space
        # after ";"   
        set req.http.Cookie = regsuball(req.http.Cookie, ";(SESS[a-z0-9]+|SSESS[a-z0-9]+|NO_CACHE)=", "; \1=");
        # 4. We remove all cookies with no space after ";", so basically we remove all cookies other
        # than those above.
        set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
        # 5. We strip leading and trailing whitespace and semicolons.
        set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");
 
        # If there are no cookies after our striping procedure, we remove the header altogether,
        # thus allowing Varnish to cache this page
        if (req.http.Cookie == "") {
            unset req.http.Cookie;
        }
        # if any of our cookies of interest are still there, we disable caching and pass the request
        # straight to Apache and Drupal
        else {
            return (pass);
        }
    }
}

. . .

次のメソッドはvcl_backend_responseです。 このメソッドは、ApacheとDrupalからの応答を処理してから、キャッシュに入れたり、キャッシュから破棄したりします。 Drupalが送信するものを変更して、キャッシュ戦略に適合させることができます。

デフォルトのメソッドは次のようになります。

. . .

sub vcl_backend_response {
    # Happens after we have read the response headers from the backend.
    #
    # Here you clean the response headers, removing silly Set-Cookie headers
    # and other mistakes your backend does.
}

. . .

そのままこのまったく新しいブロックに置き換えましょう。 コメントが含まれています:

. . .

sub vcl_backend_response {
    # Remove cookies for stylesheets, scripts and images used throughout the site.
    # Removing cookies will allow Varnish to cache those files. It is uncommon for
    # static files to contain cookies, but it is possible for files generated
    # dynamically by Drupal. Those cookies are unnecessary, but could prevent files
    # from being cached.
    if (bereq.url ~ "(?i)\.(css|js|jpg|jpeg|gif|png|ico)(\?.*)?$") {
        unset beresp.http.set-cookie;
    }
}

. . .

このコードは、以前と同じ方法でファイルを選択して静的ファイルのCookieを削除するため、vcl_recvvcl_backend_responseの両方で同じファイルのCookieが削除されます。

CTRL + x y Enterの順に構成ファイルを保存しましょう。 他の方法を変更する必要はありません。

ステップ5—ワニスを再起動する

Varnish を再起動して、変更を有効にします。

sudo service varnish restart

Varnishサーバーはエラーなしで再起動するはずです。

これで、ブラウザでDrupalWebサイトを再度表示できるようになります。

ただし、Drupalサイトが適切にキャッシュされる前に、処理する必要があるステップよりも1つ多くのステップがあります。 Drupal自体でキャッシュを有効にする必要があります。

ステップ6—Drupalでキャッシュを有効にする

デフォルトでは、Drupalのキャッシュメカニズムは無効になっています。 これにより、ヘッダーがVarnishに送信され、ページがまったくキャッシュされなくなります。 したがって、無効にされたDrupalキャッシュは、Varnishがサイトの高速化に役立つことを自動的にブロックします。

Drupalキャッシュを有効にするには、管理者としてDrupalサイトにログインします。

構成メニューを選択し、次にパフォーマンスを選択します。

Drupal Configuration menu

パフォーマンスセクションで、匿名ユーザーのキャッシュページおよびキャッシュブロックの設定を見つけて確認します。

最小キャッシュライフタイムおよびキャッシュページの有効期限30分などの適切な値に設定します。 この値により、パフォーマンスが大幅に向上しますが、キャッシュが長期間古くなっていないことを確認できます。 キャッシュの有効期間の最適な設定は、個々のサイトと更新される頻度によって異なります。 値を変更した後、構成の保存をクリックします。

Cache settings

これで、VarnishがDrupalサイトをキャッシュするために必要な構成が完了しました。

ステップ7—ワニスの構成を確認する

Varnishがサイトをキャッシュしていることを確認するには、 Varnishは機能していますか?という簡単なツールを使用できます。 フォームにウェブサイトのアドレスを入力します。 次のような応答が表示されます。

Working Varnish

「ある種の」メッセージを最初に受け取った場合は、2回確認することをお勧めします。

参考文献

この記事で取り上げるトピックは、氷山の一角にすぎません。 Varnish は非常に強力なソフトウェアであり、単なるキャッシュ以上の機能を提供します。 公式のVarnishドキュメントは、Varnishの可能性とVCL構文に関する膨大なリソースです。 ワニスとDrupalを最大限に活用するには、パフォーマンスの向上という点でDrupal自身の可能性を知ることも最善です。 公式のDrupalパフォーマンスドキュメントは良い出発点です。

ワニスはサイトのパフォーマンスを大幅に向上させるツールですが、最終的にはすべてのパフォーマンスのボトルネックに対する魔法の解決策ではなく、すべての段階で慎重に計画することで最良の結果が得られます。 そうは言っても、最も単純な Varnish 構成でも、数分でサイトをスッキリさせることができます。