Ubuntu 14.04およびDebian 7でVarnish 4を使用してDrupal 7 Webサイトを高速化する方法

前書き

バックグラウンド

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

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

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

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

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

この記事は* Ubuntu 14.04 でテストされましたが、 Debian 7 *での小さなパス変更でも動作するはずです。 他のディストリビューションでも若干の変更を加えて動作する場合があります。

ニスキャッシュ

*ワニス*はキャッシュです。つまり、その役割は、コンテンツに初めてアクセスしたときにWebアプリケーションがユーザーに提供するものを保存して記憶することです。 その後、Webアプリケーションに再度問い合わせることなく、後続のリクエストに対して同じコンテンツを*再び*提供できます。

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

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

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

前提条件

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

  • * Ubuntu 14.04 または Debian 7 *ドロップレット(Ubuntu 14.04でテスト済み)

  • sudoユーザー

  • LAMP

  • Drupal

ステップ1-Apacheの再構成

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

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

デフォルトで* Apache がリッスンするポートは、という名前のファイルに設定されます。このファイルは、 Debian Ubuntu *の両方で `+ / etc / apache2 +`にあります。

ファイルを編集します。

sudo nano /etc/apache2/ports.conf

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

# 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 *:
Listen

<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 [email protected]

前と同じように、数値を* 80 から 81 *に変更する必要があります。

<VirtualHost *:>
       ServerAdmin [email protected]
  • CTRL-x に続いて y および Enter *を使用してファイルを保存します。

Apache設定のリロード

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

sudo service apache2 reload

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

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

サイトを高速化するために、*ワニス*をインストールして構成する準備ができました。

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

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

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

sudo apt-get install apt-transport-https

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

インストールされたパッケージの信頼性を確認するには、Varnish Package Serverの公開キーをインストールする必要があります。 まず、* 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でニスをリッスンさせる

デフォルトでは、ワニスはポート* 6081 でリッスンします。 Varnishが代わりにポート 80 でリッスンするようにし、以前の Apache *と同じように、Webユーザーからのすべての着信要求を取得します。

以下を使用して、ワニス構成ファイルを開きましょう。

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"

. . .

ポート* 80 *を使用するように行を更新します( `+ \ +`も保持することを忘れないでください):

. . .

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

. . .
  • CTRL-x および y に続いて Enter *を使用してファイルを保存します。

変更を有効にするために* Varnish *を再起動します。

sudo service varnish restart

エラーのない次のようなメッセージが表示されます。

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

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

Error 503 Backend fetch failed

Backend fetch failed

Guru Meditation:
XID: 131081

Varnish cache server

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

ワニスの仕組み

*ワニス*をしっかりと理解するための優れたリソースは、公式のhttps://www.varnish-software.com/static/book/index.html [ワニスの本]ですが、その方法に関する基本的な事実をいくつか取り上げます。 *ワニス*はここで動作します。

また、今すぐインストールを完了し、後で詳しく知りたい場合は、次のステップに進んでください。 ただし、ワニスの仕組みを学べば、次のステップをより深く理解できます。

VCL言語

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

設定は、他の設定内容とともに、着信Web要求を処理するさまざまな瞬間に実行される_methods_で構成されます。

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

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

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

  • VCL *を使用すると、多くの要因に基づいて異なるキャッシングを決定する複雑なロジックを構築できます。 非常に簡単な一連の指示を作成することもできます。

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

キャッシュされるものとされないもの

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

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

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

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

*ワニス*がコンテンツをキャッシュするかどうかを決定するのに役立つ一般的な要因をいくつか見ていきましょう。

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

デフォルトのシナリオでは、基本的な前提は、ワニスが*すべて*をキャッシュすることです。 Varnishのキャッシュは、_include_ではなく_exclusive_です。つまり、ルールを作成しない限り、すべてがキャッシュされます。

リクエスト方法

リクエストメソッドは、リクエストの基本的な定義です。 デフォルトでは、GET_および_HEAD_リクエストのみをキャッシュし、_POST _、 PUT DELETE_などのその他のリクエストは*キャッシュしない*ようにします。 これにより、データに何らかの変更を加えることを目的としたリクエストが、キャッシュされずにそのままアプリケーションに到達するようになります。

承認

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

キャッシュヘッダー

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

クッキー

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

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

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

ステップ4-Drupal用のニスの構成

Varnishでのキャッシュの仕組みを基本的に理解したら、Drupalサイトで動作するようにVarnishを構成することに進みます。

Varnish VCL構成ファイルを開きます。

sudo nano /etc/varnish/default.vcl

デフォルトのコンテンツには、すべてのVarnishメソッドが空で表示されます。つまり、デフォルトが使用されています。

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

最初のブロックは、バックエンドWebサーバーへの接続方法をVarnishに指示します。この例では、* Drupal インストール済みの Apache です。 * Apache *の設定に使用したポート 81 *を反映するようにコードを変更します。

. . .

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

. . .

次に、空のプレースホルダーメソッド `+ 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.
}

. . .

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

  1. Drupalに障害が発生した場合に、ワニスが古い(古い)キャッシュコンテンツを提供できるようにします。 Drupalが応答しなくても、サイトが部分的に利用可能になります

  2. 管理ページがまったくキャッシュされていないことを確認し、特定のURLの場合はVarnishにキャッシュをスキップさせます

  3. 画像、スクリプト、スタイルシートなどの静的ファイルのキャッシュを確保する

  4. Drupalが適切に機能するために必要ないくつかのCookie(ユーザーログイン機能を含む)以外のすべてのCookieを削除

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

. . .

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);
       }
   }
}

. . .

次のメソッドはです。 このメソッドは、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を削除するため、との両方で同じファイルのCookieが削除されます。

  • CTRL + x で構成ファイルを保存し、 y に続いて Enter *を保存します。 他の方法を変更する必要はありません。

ステップ5-ニスの再起動

変更を有効にするために* Varnish *を再起動します。

sudo service varnish restart

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

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

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

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

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

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

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

image:https://assets.digitalocean.com/articles/drupal_varnish/1.png [Drupal設定メニュー]

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

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

image:https://assets.digitalocean.com/articles/drupal_varnish/2.png [キャッシュ設定]

これで、ワニスをDrupalサイトにキャッシュするために必要な設定が完了しました。

手順7-ワニスの構成の確認

Varnishがサイトをキャッシュしていることを確認するには、http://www.isvarnishworking.com/ [Is Varnish Working?]というシンプルなツールを使用できます。 フォームにウェブサイトのアドレスを入力します。 以下のような応答が表示されるはずです。

image:https://assets.digitalocean.com/articles/drupal_varnish/3.png [Working Varnish]

初めて "sort of"メッセージを受け取った場合は、2回確認することをお勧めします。

参考文献

この記事で取り上げるトピックは、氷山の一角にすぎません。 *ワニス*は非常に強力なソフトウェアであり、単なるキャッシング以上のものを提供できます。 公式のhttps://www.varnish-cache.org/docs/4.0/ [ニスのドキュメント]は、ニスの可能性とVCL構文に関する膨大なリソースです。 VarnishとDrupalを最大限に活用するには、パフォーマンスを改善するという点でDrupal自身の可能性を知ることも最適です。 公式のhttps://www.drupal.org/node/627252[Drupalパフォーマンスのドキュメント]は良い出発点です。

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

Related