このチュートリアルでは、高トラフィックのウェブサイト用のサーバクラスタを設定します。これは3つのWebアプリケーションサーバーと1つのロードバランシングサーバーで構成されています。
本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。
Alibaba Cloud Tech Share 執筆、 Jeff Cleverley。
このシリーズのチュートリアルでは、高トラフィックの Web アプリケーションや企業のビジネスサイトに適した水平方向にスケーラブルなサーバクラスタをセットアップします。クラスタは 3 台の Web アプリケーションサーバと 1 台のロードバランシングサーバで構成されています。クラスタ上にWordPressを設定してインストールしますが、実際のクラスタ構成はPHPベースのWebアプリケーションに適しています。各サーバーは LEMP スタック(Linux、Nginx、MySQL、PHP)を実行します。
このチュートリアルを完了するには、このシリーズの最初の2つのチュートリアルを完了している必要があります。
最初のチュートリアルでは、3台のノードサーバと負荷分散用のサーバをプロビジョニングしました。ノードサーバーでは、データベースとWebアプリケーションのファイルシステムのレプリケーションを設定しました。サーバー間のリアルタイムのデータベース同期を提供するために、MySQLの代替としてPercona XtraDB Cluster Databaseを使用しました。ウェブアプリケーションファイルのレプリケーションとサーバ間の同期のために、GlusterFS分散ファイルシステムをセットアップしました。
2回目のチュートリアルでは、PHP7とNginxをインストールしてLEMPスタックのインストールを完了し、各ノードとロードバランサーにNginxを設定し、ドメインのロードバランサーにLet's encrypt SSL証明書を発行し、クラスタにWordPressをインストールしました。
これで、各ノード間で均等に負荷が分散された WordPress クラスタが完成しました。
最後のチュートリアルでは、管理トラフィックをノード1に、一般的なサイトトラフィックをノード2に向け、より高度なクラスタアーキテクチャの構成を見ていきます。これにより、Web アプリケーションの管理で行われているシーンの背後で行われている CPU やリソースを集中的に消費する作業が、サイトトラフィックのレスポンスに影響を与えることがないようになります。
このチュートリアルが完了すると、以下のようなクラスタアーキテクチャになります。
<管理者のトラフィックとサイトのトラフィックをリダイレクトするロードバランサを備えた3ノードクラスター>
さらに、パフォーマンスを向上させるために Nginx FastCGi のキャッシングを追加し、クラスタに極端な負荷がかかっても良いように、データベースクラスタと分散ファイルシステムを強化していきます。
もしスーパーユーザを使用している場合は、必要に応じてコマンドの前にsudoコマンドを追加することを忘れないでください。私はまた、テストドメイン'yet-another-example.com'を使用しますが、コマンドを発行する際には、これをあなたのドメインに置き換えることを忘れないでください。
コマンドでは、私のサーバのプライベートIPアドレスとパブリックIPアドレスを使用します。
このチュートリアルは最初の2つのチュートリアルに直接従っているので、手順の順序はそれに応じて番号が付けられています。ステップ1から3は最初のチュートリアルにあり、ステップ4から7は2番目のチュートリアルにあります。このチュートリアルはステップ8から始まります。
高度な設定
ステップ8: Nginx FastCGIキャッシングを設定する
現在の構成では、ウェブアプリケーションは3台のサーバのクラスタから提供されています。この水平方向のスケーリングにより、サイトは膨大な負荷に耐えられるようになり、新しいサーバでの追加スケーリングや古いサーバの簡単なスワップアウトが可能になります。
Nginx FastCGI キャッシングを利用することで、さらにパフォーマンスを向上させることができます。
サイトを訪問し、インスペクターのネットワークタブを開き、サイトをリロードすると、ページの読み込み速度が確認できるでしょう。
<ネットワークタブでサイトの負荷を確認する>
私の場合、1.91秒でサイトが読み込まれています。
サイトトラフィックを処理する各ノードで、WordPress サイトのバーチャルホスト Nginx 設定ファイルを開いて編集します。
この例では、node1 は管理タスクに使用されるため、キャッシュは必要ありません。そのため、ノード2とノード3で以下のコマンドを実行します。
# nano /etc/nginx/yet-another-example.com
サーバーブロックの上に以下を追加します。
fastcgi_cache_path /var/run/nginx-fastcgi-cache levels=1:2 keys_zone=FASTCGICACHE:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
これは、RAM にマウントされている /var/run/ ディレクトリにキャッシュを作成し、キャッシュに key_zone の識別子を与えます。fastcgi_cache_use-stale は、PHP のタイムアウトや http 500 のエラーが発生した場合でも、キャッシュされたページを提供し続けるようにサーバに指示します。Nginx のキャッシュ機能は非常に優れています。
サーバーブロックの中で、エラーログの下と最初のロケーションブロックの上に以下を追加してください。
set $skip_cache 0;
# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
set $skip_cache 1;
}
if ($query_string != "") {
set $skip_cache 1;
}
# Don't cache uris containing the following segments
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
set $skip_cache 1;
}
# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}
これらは、WordPress の異なる機能のために特定のキャッシュの省略を設定します。
最後に、'location ~ /.php$' ブロック内に以下を追加します。
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache FASTCGICACHE;
fastcgi_cache_valid 60m;
add_header X-FastCGI-Cache $upstream_cache_status;
fastcgi_cache ディレクティブはサーバブロックの上のコードブロックの keys_zone にマッチしなければなりません。 fastcgi_cache_valid はキャッシュを保持する時間を設定します。
完全な設定ファイルは以下のようになっているはずです。
fastcgi_cache_path /var/run/nginx-fastcgi-cache levels=1:2 keys_zone=FASTCGICACHE:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
server {
listen 80;
listen [::]:80;
root /var/www/yet-another-example.com;
index index.php index.htm index.html;
server_name _;
access_log /var/log/nginx/yetanotherexample_access.log;
error_log /var/log/nginx/yetanotherexample_error.log;
set $skip_cache 0;
# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
set $skip_cache 1;
}
if ($query_string != "") {
set $skip_cache 1;
}
# Don't cache uris containing the following segments
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
set $skip_cache 1;
}
# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache FASTCGICACHE;
fastcgi_cache_valid 60m;
add_header X-FastCGI-Cache $upstream_cache_status;
}
location ~ /\.ht {
deny all;
}
location = /favicon.ico { log_not_found off; access_log off; }
location = /robots.txt { log_not_found off; access_log off; allow all; }
location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
expires max;
log_not_found off;
}
}
端末では以下のようになっているはずです。
<FastCGIキャッシュを有効にしたNginxバーチャルホスト設定ファイル>
ファイルを保存して終了し、これまで通り、リロードする前に構文エラーがないかチェックしてください。
# nginx -t
# service nginx reload
ここで、ネットワークインスペクタタブを開いた状態でサイトをリロードします。
<FastCGIキャッシングでリロードしてサイトを検査する>
ご覧の通り、私のサイトは以前の3分の1近くの時間でロードされるようになりました。693msでロードすると、ロード時間が1.3秒短縮されました。
ステップ9: 管理者ノードと訪問者ノードを設定する
現在のところ、私たちのクラスタはバランス構成で構成されています。ロードバランサは各ノードサーバに等しくトラフィックを提供します。
必要に応じてトラフィックに重みをつけて、いくつかのサーバにはより多くのトラフィックを、他のサーバにはより少ないトラフィックを提供することができます。しかし、ノード2と3にはサイトトラフィックを均等に供給し、ノード1は管理用に確保しておきます。
前述したように、WordPress のようなウェブアプリケーションの実行に関連する管理タスクの多くは、貴重なリソースを消費し、サーバの速度低下につながる可能性があります。これは、管理タスクが実行されているのと同じサーバーからページを提供されている場合、サイトへの訪問者に悪影響を及ぼす可能性があります。私たちが選択したクラスタアーキテクチャは、このようなことが起こらないようにし、さらに規模を拡大する必要がある場合には、サイト訪問者のノードを簡単に追加することができます。
セキュリティグループで別のポートを開く
Alibaba Cloud Management Consoleでセキュリティグループにアクセスし、別のインバウンドポートを開きます。
- ポート 9443/9443 - 認証オブジェクト 0.0.0.0.0/0
<ノード1への管理者アクセスのためのポートを開く>
ロードバランサーのNginxバーチャルホスト設定ファイルを再設定
ロードバランサー上で Nginx の設定ファイルを開いて編集します。
# nano /etc/nginx/sites-available/yet-another-example.com
設定ファイルの中に新しいアップストリームブロックを追加し、node1のプライベートIPを追加します。
# Cluster Admin - Only accessible by port 9443 - reserves this node of Admin activities
upstream clusterwpadmin {
server 172.20.62.56;
}
ここでnode1のプライベートIPをclusternodesアップストリームブロックから削除します。
# Clusternodes - public facing for serving the site to visitors
upstream clusternodes {
ip_hash;
server 172.20.213.159;
server 172.20.213.160;
}
既存のサーバーブロックの下に、以下のコードで管理者ポートをリッスンするためのサーバーブロックを追加します。
# Admin connection to yourdomain.com:9443 they will be directed to node 1.
server {
listen 9443 ssl;
server_name yet-another-example.com www.yet-another-example.com;
ssl_certificate /etc/letsencrypt/live/yet-another-example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/yet-another-example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
if ($scheme != "https") {
return 301 https://$host$request_uri;
} # managed by Certbot
location / {
proxy_pass http://clusterwpadmin;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
}
}
このブロックが Certbot からの SSL ディレクティブにアクセスできるようにし、proxy_pass が 'clusterwpadmin' アップストリームサーバーに向けられていることを確認してください。
これで設定ファイル全体は以下のようになるはずです。
# Cluster Admin - Only accessible by port 9443 - reserves this node of Admin activities
upstream clusterwpadmin {
server 172.20.62.56;
}
# Clusternodes - public facing for serving the site to visitors
upstream clusternodes {
ip_hash;
server 172.20.213.159;
server 172.20.213.160;
}
server {
listen 80;
server_name yet-another-example.com www.yet-another-example.com;
location / {
proxy_pass http://clusternodes;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/yet-another-example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/yet-another-example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
if ($scheme != "https") {
return 301 https://$host$request_uri;
} # managed by Certbot
# Redirect non-https traffic to https
# if ($scheme != "https") {
# return 301 https://$host$request_uri;
# } # managed by Certbot
}
# Admin connection to yourdomain.com:9443 they will be directed to node 1.
server {
listen 9443 ssl;
server_name yet-another-example.com www.yet-another-example.com;
ssl_certificate /etc/letsencrypt/live/yet-another-example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/yet-another-example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
if ($scheme != "https") {
return 301 https://$host$request_uri;
} # managed by Certbot
location / {
proxy_pass http://clusterwpadmin;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
}
}
あなたの端末では以下のようになります:
<ロードバランサーNginxの管理ノード設定>
これで、URLの最後に:9443を追加することでnode1にアクセスすることができるようになりました。管理者作業用のnode1にアクセスするには、次のようにします。
https://yet-another-example:9443/wp-admin
<ノード1管理者サーバ上でのWordPress管理について>
もちろん、必要に応じて他のノードのWordPress管理画面にアクセスすることもできますが、私はそれをお勧めしません。
ステップ10. クラスタレプリケーションの安全性を確保する
私たちのクラスタでは、各ノードの Percona データベースは MySQL 3306 ポートを介して他のノードのデータベースと通信しており、特定の Percona ポート 4444,4567,4568 と共に通信しています。同様に、GlusterFS glustervolume は標準のオープン TCP ポートを介して各ノードと通信しています。
現時点では、外部サーバーはポートとボリュームの詳細を知っていれば、これらのコンポーネントと通信することができます。それらをセキュアにする必要があります。
Percona データベースのレプリケーションポートの確保
セキュリティグループでは、すべてのIPアドレス0.0.0.0.0/0にアクセスできるように、以下のポートを開放しました。
- ポート 3306 TCP (インバウンド/アウトバウンド)
- ポート 4444 TCP (インバウンド/アウトバウンド)
- ポート 4567 TCP (インバウンド/アウトバウンド)
- ポート 4568 TCP (インバウンド/アウトバウンド)
各ポートに対して個別のルールを作成する必要があります。
以下のルールを追加する必要があります。
ポート3306 x 3 - インバウンド&アウトバウンドルール
認証タイプ:アドレスフィールド 認可オブジェクト:172.20.62.56
認証タイプ:アドレスフィールド認可オブジェクト:172.20.213.159
認証タイプ:アドレスフィールド認可オブジェクト:172.20.213.160
ポート4444×3 - - インバウンド&アウトバウンドルール
認証タイプ:アドレスフィールド 認可オブジェクト:172.20.62.56
認証タイプ:アドレスフィールド認可オブジェクト:172.20.213.159
認証タイプ:アドレスフィールド認可オブジェクト:172.20.213.160
ポート4567 x 3 - - インバウンド&アウトバウンドルール
認証タイプ:アドレスフィールド 認可オブジェクト:172.20.62.56
認証タイプ:アドレスフィールド認可オブジェクト:172.20.213.159
認証タイプ:アドレスフィールド認可オブジェクト:172.20.213.160
ポート4568 x 3 - - インバウンド&アウトバウンドルール
認証タイプ:アドレスフィールド 認可オブジェクト:172.20.62.56
認証タイプ:アドレスフィールド認可オブジェクト:172.20.213.159
認証タイプ:アドレスフィールド認可オブジェクト:172.20.213.160
ここで、0.0.0.0.0.0/0 へのフルアクセスを許可している各ポートの元のルールを削除する必要があります。
セキュリティグループのインバウンドルールは次のようになります。
<Perconaのインバウンドポートの確保について>
セキュリティグループのアウトバウンドルールは次のようになります。
<Perconaのアウトバウンドポートの確保について>
安全なPerconaポートのテスト
これらのポートを使用して、プライベートIPアドレス上のノード間の通信をテストする必要があります。残念ながら、'ping' ツールはポートでは動作しないので、これには使用できません。
幸いにも 'hping3' ツールは使えるので、インストールしてください。
# apt-get install hping3
各ノードで、他のノードのIPアドレスとポートのそれぞれに対して以下のコマンドを実行します。
# hping3 <other node ip> -S -V -p <port number>
例えば、私のノード1では:
# hping3 172.20.213.159 -S -V -p 3306
# hping3 172.20.213.159 -S -V -p 4444
# hping3 172.20.213.159 -S -V -p 4567
# hping3 172.20.213.159 -S -V -p 4568
# hping3 172.20.213.160 -S -V -p 3306
# hping3 172.20.213.160 -S -V -p 4444
# hping3 172.20.213.160 -S -V -p 4567
# hping3 172.20.213.160 -S -V -p 4568
ノード上ですべてのポートが動作している場合は、以下のようなレスポンスを得る必要があります。
<ノード1からのノード2ポート3306のテストに成功>
<ノード1からノード2のポート4444のテストに成功>
<ノード1からノード2のポート4567のテストに成功しました>
<ノード1からノード2の4568番ポートのテストに成功しました>
これでPerconaクラスタ内のノードは、開いているポートとプライベートIPアドレスを介してのみ相互に通信することができます。
ノードを追加する場合は、セキュリティグループで追加のルールを設定する必要があることに注意してください。
GlusterFS ファイルシステムの保護
現時点では、ボリューム名とIP範囲を知っていれば、どのコンピュータでもストレージボリュームに接続することができますが、これを確保するのは簡単です。
ノードのプライベート IP アドレスをカンマで区切って、以下のコマンドを実行してください。
# gluster volume set glustervolume auth.allow 172.20.62.56,172.20.213.159,172.20.213.160
「成功」のメッセージが表示されるはずです。
<GlusterFSボリューム権限の設定>
セキュリティが有効になっているかどうかを確認したり、info コマンドでボリュームの詳細を確認することができます。
# gluster volume info
ご覧のように、ボリュームはノードのプライベートIPアドレスからのアクセスのみを許可しています。
<クラスタボリューム情報-アクセス制限付きについて>
これをオフにして、何らかの理由ですべてのアクセスを許可したい場合は、以下のコマンドで行います。
# gluster volume set glustervolume auth.allow all
完了!
これで完了です。3ノードを使って、パフォーマンスの高いWordPressクラスタを作成し、確保しました。GlusterFS分散ネットワークストレージシステムとPercona XtraDBクラスタデータベースを使用しています。
1つのノードはWebアプリケーションの管理用に設定し、システムcrontabでWordPress Cronのスケジュールタスクを管理し、もう1つのノードと2つのノードはサイトトラフィックを処理するために残しています。サイトトラフィックのノードには Nginx FastCGI キャッシングを使用し、高負荷時のパフォーマンスと安定性をさらに向上させています。
このアーキテクチャは、最も要求の厳しいエンタープライズサイトに簡単に対応できるように、水平方向に拡張できます。クラスタを分解して、専用の GlusterFS ノードファイルサーバと専用の Percona クラスタデータベースサーバでサービスを提供する Nginx ウェブサーバのクラスタを構築することも可能です。Redisサーバ経由で外部オブジェクトキャッシュを追加したり、専用のElasticsearchサーバに検索機能を削除したりすることもできます。これらは別のチュートリアルのトピックです。
アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ