Nginxのロードバランシング機能で、複数のWebサーバに負荷分散させる

概要

今回は、ロードバランサとしてNginxを構築した仮想マシンと、3つのApacheが稼働している仮想マシンの計2つ用意して、負荷分散させてみようと思います。

検証する前にまず、ロードバランサの定義、ロードバランシングの種類の違いについてまとめていきます。

ロードバランサとは?

ロードバランサとは、クライアントからのリクエストを、複数のサーバに振り分け、1台あたりの負荷を抑えるようにする装置のことです。イメージとしては以下のようになります。

Load Balancer

ロードバランシングの種類

Nginxがサポートしているロードバランシング(振り分け方)は以下の3種類があります。

種類説明
ラウンドロビンクライアントからのリクエストをサーバに均等に転送。
Least Connectedコネクション数が最小のサーバに転送。
IPハッシュクライアントのIPアドレスごとに転送先のサーバを固定する。

今回はラウンドロビンとIPハッシュの二つの方法を検証します。

環境

  • VirtualBox 6.1.16
  • 仮想マシン(CentOS8) × 2
  • Nginx 1.18.0
  • Apache 2.4.37

事前準備

IPアドレス固定

度々IPアドレスが変わると面倒なので、最初にIPアドレスを固定させます。今回は、ロードバランサ側のIPアドレスを192.168.0.7とし、Webサーバ側のIPアドレスを192.168.0.9とします。

ロードバランサ側(Nginx)

インターフェース名を確認し(enp0s3)、nmcliコマンドで変更していきます。コマンドの詳しい解説は以下の記事の事前準備に記述しています。

Apacheでバーチャルホスト機能を利用せず、サービス複製で複数サイトを構築する

# nmcli c m enp0s3 ipv4.address 192.168.0.7/24
# nmcli c m enp0s3 ipv4.gateway 192.168.0.1
# nmcli c m enp0s3 ipv4.dns 192.168.0.1
# nmcli c m enp0s3 ipv4.method manual
# nmcli c u enp0s3 
# ip a
---------(省略)------------
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:c1:f9:16 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.7/24 brd 192.168.0.255 scope global noprefixroute enp0s3
       valid_lft forever preferred_lft forever
---------(省略)-------------

Webサーバ側(Apache)

# nmcli c m enp0s3 ipv4.address 192.168.0.9/24
# nmcli c m enp0s3 ipv4.gateway 192.168.0.1
# nmcli c m enp0s3 ipv4.dns 192.168.0.1
# nmcli c m enp0s3 ipv4.method manual
# nmcli c u enp0s3 
# ip a
-----------(省略)-------------
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:6c:d9:ed brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.9/24 brd 192.168.0.255 scope global noprefixroute enp0s3
       valid_lft forever preferred_lft forever
-----------(省略)-------------

SELinux 無効化

ロードバランサ側&Webサーバ側

getenforceコマンドでSELinuxが起動していることが確認できた場合は、/etc/selinux/configファイルを以下のように編集し、再起動させます。

# getenforce
enforcing

# vi /etc/selinux/config
-----(省略)--------
SELINUX=disabled

:wq!

# reboot

/etc/hosts 編集

IPアドレスのままでいい方は、ここはスルーして全然問題ないです。自分はWebサーバのドメインをweb1.example.comにします。そのため、名前解決できるように、ホストOS側(ここのWebブラウザで動作確認するため)、ロードバランサ側、Webサーバ側で/etc/hostsを編集します。

# vi /etc/hosts
-------(省略)---------
192.168.0.9 web1.example.com

:wq!

No1.Apache

まず最初に1つ目のApacheを構築していきます。

インストール

# dnf install httpd

ファイアウォール設定

# firewall-cmd --add-service=http --zone=public --permanent
success
# firewall-cmd --add-service=https --zone=public --permanent
success
# firewall-cmd --reload 
success

動作確認

自動起動&今すぐ起動の設定をします。

# systemctl enable httpd --now

後の検証で分かりやすいように、No1.Apache = オレンジとしています。/var/www/html/index.htmlを以下のように編集します。

# vi /var/www/html/index.html
<body bgcolor="#FF6633" text="#ffffff">
<h1>No1.Apache</h1>
<h1>192.168.0.9:80</h1>
</body>

curlコマンドで取得できるか確認します。

# curl http://web1.example.com
<body bgcolor="#FF6633" text="#ffffff">
<h1>No1.Apache</h1>
<h1>192.168.0.9:80</h1>
</body>

OKだったので、ホストOS側のWebブラウザからweb1.example.com(192.168.0.9)にアクセスして以下の画面が表示されることも確認します。

No2.Apache

Apacheの複製は、以下の記事の方法で行っています。

Apacheでバーチャルホスト機能を利用せず、サービス複製で複数サイトを構築する

詳しい説明はここでしているので、今回は簡単な説明で進めていきます。

サービスの複製

最初に構築したApacheの基本設定ファイルやディレクトリをコピーして、No2.Apache用に編集します。

# cd /etc
# cp -rp httpd httpd2
# cd httpd2/conf
# vi httpd.conf
ServerRoot "/etc/httpd2"

PidFile run/httpd2.pid

Listen 8080

ServerName localhost:8080

DocumentRoot "/var/www/html2"

<Directory "/var/www/html2">
   Options FollowSymLinks

   AllowOverride None

   Require all granted
</Directory>

ErrorLog "logs/error_log2"

<IfModule log_config_module>
   CustomLog "logs/access_log2" combined
</IfModule>

以下のコマンドで構文チェックを行い、エラーが出なければOKです。

# apachectl configtest
Syntax OK

/var/www以下もNo2.Apache用でhtml2として既存のhtmlをコピーして編集します。No2.Apache = 緑としています。

# cd /var/www
# cp -rp html html2
# vi html2/index.html
<body bgcolor="#99CC66" text="#ffffff">
<h1>web2.example.com</h1>
<h1>192.168.0.9:8080</h1>
</body>

:wq!

systemctlコマンドで起動や停止したりするために、ユニットファイルを作成します。これも既存のファイルのコピーをして編集です。

# cp -p /usr/lib/systemd/system/httpd.service /usr/lib/systemd/system/httpd2.service
# vi /usr/lib/systemd/system/httpd2.service
------(省略)------
ExecStart=/usr/sbin/httpd -f /etc/httpd2/conf/httpd.conf $OPTIONS -DFOREGROUND
ExecReload=/usr/sbin/httpd -f /etc/httpd2/conf/httpd.conf $OPTIONS -k graceful

:wq!

以下のコマンドで新しく作成したユニットファイルを認識させます。

# systemctl daemon-reload

No2.Apacheは8080番で待ち受けることにするので、ここを開放してあげます。

# # firewall-cmd --add-port=8080/tcp --zone=public --permanent
success
# firewall-cmd --reload
success

自動起動&今すぐ起動の設定をします。

# systemctl enable httpd2 --now

動作確認

では、curlコマンドで、web1.example.com:8080にアクセスし、ページが取得できることを確認します。

# curl http://web1.example.com:8080
<body bgcolor="#99CC66" text="#ffffff">
<h1>No2.Apache</h1>
<h1>192.168.0.9:8080</h1>
</body>

Webブラウザからも確認します。

No3.Apache

手順はNo2.Apacheと全く一緒で、No3.Apache用にちょこっと変えるだけなので説明は省きます。No3.Apache = 青としています。

サービスの複製

# cd /etc
# cp -rp httpd httpd3
# cd httpd3/conf
# vi httpd.conf
ServerRoot "/etc/httpd3"

PidFile run/httpd3.pid

Listen 8081

ServerName localhost:8081

DocumentRoot "/var/www/html3"

<Directory "/var/www/html3">
   Options FollowSymLinks

   AllowOverride None

   Require all granted
</Directory>

ErrorLog "logs/error_log3"

<IfModule log_config_module>
   CustomLog "logs/access_log3" combined
</IfModule>
# apachectl configtest
Syntax OK
# cd /var/www
# cp -rp html html3
# vi html3/index.html
<body bgcolor="#6699FF" text="#ffffff">
<h1>No3.Apache</h1>
<h1>192.168.0.9:8081</h1>
</body>

:wq!
# cp -p /usr/lib/systemd/system/httpd.service /usr/lib/systemd/system/httpd3.service
# vi /usr/lib/systemd/system/httpd3.service
------(省略)------
ExecStart=/usr/sbin/httpd -f /etc/httpd3/conf/httpd.conf $OPTIONS -DFOREGROUND
ExecReload=/usr/sbin/httpd -f /etc/httpd3/conf/httpd.conf $OPTIONS -k graceful

:wq!
# systemctl daemon-reload
# # firewall-cmd --add-port=8081/tcp --zone=public --permanent
success
# firewall-cmd --reload
success
# systemctl enable httpd3 --now

動作確認

# curl http://web1.example.com:8081
<body bgcolor="#6699FF" text="#ffffff">
<h1>No3.Apache</h1>
<h1>192.168.0.9:8081</h1>
</body>

Nginx

ここからはロードバランサ側(192.168.0.7)の構築をしていきます。

インストール

前回と同様、今回も最新の安定版を取得するために、リポジトリに新しく登録してインストールしていきます。

# cd /etc/yum.repos.d/
# vi nginx.repo
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
# dnf install nginx
# nginx -v
nginx version: nginx/1.18.0

ファイアウォール設定

あとでまた開放するポートはありますが、ここでは簡単な動作確認のためにhttp通信用のポートを開放するだけにします。

# firewall-cmd --add-service=http --zone=public --permanent
success
# firewall-cmd --add-service=https --zone=public --permanent
success
# firewall-cmd --reload
success

動作確認

自動起動&起動の設定をします。

# systemctl enable nginx --now

Apacheの場合は表示させたいページを/var/www/htmlディレクトリ以下に置きましたが、Nginxでは/usr/share/nginx/htmlディレクトリ以下に置きます。

分かりやすいようにロードバランサ = 黒としています。

# cd /usr/share/nginx/html
# vi index.html
<body bgcolor="#000000" text="#ffffff">
<h1>Nginx Load Balancer</h1>
<h1>192.168.0.7</h1>
</body>

:wq!

まずcurlで取得できることを確認します。

# curl http://192.168.0.7
<body bgcolor="#000000" text="#ffffff">
<h1>Nginx Load Balancer</h1>
<h1>192.168.0.7</h1>
</body>

Webブラウザからも確認して、以下のような画面が表示されれば問題なしです。

ロードバランサ設定

ここからロードバランサの設定していきます。/etc/nginx/conf.dディレクトリ以下に新しくロードバランシング設定用のファイルを作成して、以下のように編集します。

# cd /etc/nginx/conf.d
# vi loadb.conf

#test1というグループ名で、バックエンドのWebサーバをグループ化する
upstream test1 {
        server web1.example.com:80;
        server web1.example.com:8080;
        server web1.example.com:8081;
}


server {
     #8082番で待ち受ける
        listen 8082;
        server_name localhost;
     
        location / {
         #ルートディレクトリへのアクセスは、test1グループに転送させる
                proxy_pass http://test1;
        }
}

#test2というグループ名で、バックエンドのWebサーバをグループ化する
upstream test2 {
     #IPハッシュを使用する(方法を明記していない場合は、ラウンドロビン)
        ip_hash;
        server web1.example.com:80;
        server web1.example.com:8080;
        server web1.example.com:8081;
}

server {
        listen 8083;
        server_name localhost;

        location / {
                #ルートディレクトリへのアクセスは、test2グループに転送させる
                proxy_pass http://test2;
        }
}

編集できたら、以下のコマンドで構文チェックを行います。

# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

8082番がラウンドロビンの待ち受けポート、8083番がIPハッシュの待ち受けポートとするので、以下のコマンドで開放してあげます。

# firewall-cmd --add-port=8082/tcp --zone=public --permanent
success
# firewall-cmd --add-port=8083/tcp --zone=public --permanent
success
# firewall-cmd --reload
success

設定の最後にNginxを再起動させます。

# systemctl restart nginx

ラウンドロビン検証

ではまず、ラウンドロビンから検証していきます。ラウンドロビンはバックエンドのWebサーバに均等に負荷分散させるため、連続で同じWebサーバにリクエストを転送するといったことは無いはずです。

まずはcurlコマンドで3回ページを取得してみます。

# curl http://192.168.0.7:8082
<body bgcolor="#FF6633" text="#ffffff">
<h1>No1.Apache</h1>
<h1>192.168.0.9:80</h1>
</body>

# curl http://192.168.0.7:8082
<body bgcolor="#99CC66" text="#ffffff">
<h1>No2.Apache</h1>
<h1>192.168.0.9:8080</h1>
</body>

# curl http://192.168.0.7:8082
<body bgcolor="#6699FF" text="#ffffff">
<h1>No3.Apache</h1>
<h1>192.168.0.9:8081</h1>
</body>

このように、No.1、No.2、No.3といったように均等に振り分けていることが確認できます。

では、Webブラウザからも3回アクセスしてみます。(192.168.0.7:8082)

アクセス1回目
アクセス2回目
アクセス3回目

Webブラウザ上からも無事確認することができました。

IPハッシュ検証

では最後にIPハッシュを検証していきます。IPハッシュの場合は、クライアントのIPアドレスが変わらない限り、ずっと同じWebサーバに振り分けられるので、コロコロ変わることは無いはずです。

まずはcurlで3回ページを取得してきます。

# curl http://192.168.0.7:8083
<body bgcolor="#FF6633" text="#ffffff">
<h1>No1.Apache</h1>
<h1>192.168.0.9:80</h1>
</body>

# curl http://192.168.0.7:8083
<body bgcolor="#FF6633" text="#ffffff">
<h1>No1.Apache</h1>
<h1>192.168.0.9:80</h1>
</body>

# curl http://192.168.0.7:8083
<body bgcolor="#FF6633" text="#ffffff">
<h1>No1.Apache</h1>
<h1>192.168.0.9:80</h1>
</body>

予想通りしっかりと固定されています。

Webブラウザからも3回アクセスしてみます。(192.168.0.7:8083)

アクセス1回目
画像に alt 属性が指定されていません。ファイル名: スクリーンショット-2020-11-22-17.42.25.png
アクセス2回目
画像に alt 属性が指定されていません。ファイル名: スクリーンショット-2020-11-22-17.42.25.png
アクセス3回目

3回ともNo1.Apacheなので固定されていることが確認できました。

以上、Nginxのロードバランシング機能で、3つのWebサーバに負荷分散させることができました。

参考文献

【Linux技術動画】Webサーバの負荷分散?Nginxでロードバランサーの説明・構築動画 ※約20分

標準テキスト CentOS7 構築・運用・管理パーフェクトガイド

Linux教科書 LPIC レベル2 Version4.5対応

Nginxのロードバランシング機能を使ってみよう – 株式会社 ネディア

Comments

Copied title and URL