↔️

WEBサーバがロードバランサーの役割をする?

2024/10/22に公開

はじめに

こんにちは。
情報系学部所属のインターン生です!

現在は、インターン先で自社WEBアプリ開発のログイン機能を作成中です。
セッション管理について調べているときに、ロードバランサー、パーシステンスなどの機能が出てきて、わからないことだらけだったので、ここにまとめます!

ロードバランサーとは

外部からの通信を複数のサーバーに分散する装置
例: HAProxy、AWSのELB(Elastic Load Balancing)

ロードバランサーの機能

ロードバランサーの機能はいくつもあるが、そのうちの役割が大きいと思ったものを記載。

機能➊ 負荷分散

ユーザからアクセスがあった際にそれらのアクセスを複数のサーバに振り分けること。
下のイラストのように、ロードバランサーがないと、アクセスを振り分けることができない。そのため、アクセスが集中した際は、サーバが重くなったり、最悪の場合は、止まってしまう。

ロードバランサーを用いて、アクセスをいくつかのサーバに振り分けることで、1台のサーバにかかる負荷を軽減できる。
そのため、処理が速くなり、ホームページがすぐに表示されるなど、快適になる。(UX向上)

機能➋ サービスの停止を防ぐ

停止したサーバへのアクセスを遮断できる。
サーバが1台しかないと、そのサーバが停止した際に、そのサービスが使えなくなってしまう。
※サーバは、物理的にハードウェアが壊れたり、ソフトウェアのバク、大量アクセスなどにより、停止してしまうことがある。

しかし、ロードバランサーを使って複数台のサーバを動作させることで、あるサーバが仮に止まってしまっても、他のサーバが稼働している限り、サービスが止まることはない。

機能➌ パーシステンス

同一のユーザーからのリクエストを常に同じサーバーに転送するセッション維持機能。
この機能により、ユーザーの一連のアクセスを同じサーバーで処理することができる。

複数のサーバーを使って運用している場合、一つのサーバーにセッション情報を保存してしまうと、次回のアクセス時に別のサーバーに接続された際、前回のセッション情報が引き継がれず、ユーザーに応じた処理ができなくなる。
その問題をパーシステンスという機能により、解決できる。

以下のイラストのようにユーザAがサーバXにアクセスしたことがある場合、再度ユーザAを同じサーバXにアクセスするように振り分けることができる。
それにより、セッション管理など、そのユーザに基づいた処理が可能となる。

この方法として、ユーザのIPアドレスを用いて割り振る方法や、cookie、URLなど特定の情報に基づいてユーザを割り振る方法がある。

セッションについては、以下の記事で詳しく記載している。
https://zenn.dev/mojitakanori/articles/248168c0bf8217

WEBサーバとは

クライアント(ユーザーのブラウザなど)からのリクエストに応じて、WebページやAPIのデータを返す役割を持つ。
動作: 静的ファイル(HTML、CSS、JavaScriptなど)や動的コンテンツ(PHP、Python、Node.jsなどを使ったWebアプリケーション)を提供。
: Apache、Nginx

WEBサーバがロードバランサーになれる。

WEBサーバ(ApacheやNginx)も設定することによりロードバランサーの機能を実現できる。
WEBサーバにロードバランサーの機能を持たせて、アクセスを複数のバックアップサーバに振り分けることができる。

Apache:「mod_proxy_balancer」というモジュールがあり、これを使うことで実現できる。
Nginx:デフォルトでロードバランシング機能をサポートしているため、設定ファイル(nginx.conf)にロードバランシングの設定を追加するだけで実現できる。

何が違うのか

WEBサーバのロードバランサー機能:簡単なロードバランサーとして機能することができますが、これらは、あくまで追加の機能。小規模なシステムや簡易的な負荷分散には十分だが、複雑な分散やスケーラビリティが求められる大規模システムには向かない場合がある。

ロードバランサー:は、トラフィックの分散に特化した設計であり、より高度な機能、パフォーマンスを提供する。大規模システムや高負荷のシステムでは、専用のロードバランサーの方が適している場合が多い。

実際にロードバランサーの機能を体感してみた

知識として知っておくだけでなく、実際に触って動かしてみた方が理解が深まると思うので、ローカルで動かしてみる!

流れ

  1. バックエンドサーバを2台稼働させる。
  2. Nginxを稼働させて、設定をする。
  3. ブラウザからNginxにアクセスして挙動を見る。
  4. (おまけ)パーシステンス機能も体感。

    構成図

バックエンドサーバを2台稼働させる。

アクセスすると、そのサーバの名前とPort番号だけを表示するサーバを稼働させる。
以下にhttp.serverモジュールを使用した簡単なサーバのコードを示す。

server(1or2).py
from http.server import SimpleHTTPRequestHandler, HTTPServer

class MyHandler(SimpleHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()
        # 以下の片方ずつを使って二台のサーバを作る!!
        # self.wfile.write(b"<html><body><h1>Backend Server 1  port 8001</h1></body></html>")
        # self.wfile.write(b"<html><body><h1>Backend Server 2  port 8002</h1></body></html>")

httpd = HTTPServer(('localhost', 8001), MyHandler)
print("Serving on port 8001...")
httpd.serve_forever()

このコードをserver1.pyとserver2.pyにそれぞれ保存する。
そして、ターミナルから実行する。

python server1.py
python server2.py

Nginxを稼働させて、設定をする

Nginx公式サイトからNginxを稼働させるためのファイルをダウンロードする。

私はWindows!

ダウンロードしたZIPフォルダを適当な場所で解凍する。
コマンドプロンプトでそのフォルダの階層に移動して、start nginxでNginxを稼働させる。

cd C:\nginx-1.26.2
start nginx  

次に、nginx-1.26.2→confフォルダにあるnginx.confという設定ファイルを修正する。
以下のように記述する。

nginx.conf
worker_processes  1;  # Nginxが使用するワーカープロセスの数
events {
    worker_connections  1024;  # 接続できる最大数
}
http {
    upstream backend_servers {
        server localhost:8001;  # バックエンドサーバ1
        server localhost:8002;  # バックエンドサーバ2
    }
    server {
        listen 8080;  # Nginxがリクエストを受け付けるポート
        location / {
            proxy_pass http://backend_servers;  # ロードバランシング対象のバックエンドサーバ
        }
    }
}

この設定を反映させるために、以下のコマンドを実行して、Nginxを再起動させる。

.\nginx.exe -s reload

ブラウザからNginxにアクセスして挙動を見る

ブラウザでhttp://localhost:8080にアクセスすると、ロードバランサーによって振り分けられたバックエンドサーバのHTMLページが表示される。

Backend Server 1 port 8001と表示されれば、バックエンドサーバ1(ポート8001)に接続されていることがわかる。
Backend Server 2 port 8002と表示されれば、バックエンドサーバ2(ポート8002)に接続されていることがわかる。

ブラウザのリロードをすると、それぞれのサーバに接続されることがわかる。

(おまけ)パーシステンス機能も体感

Nginxの設定ファイル(nginx.conf)を少し修正すると、パーシステンス機能をつけることができる。

nginx.conf
http {
    upstream backend_servers {
+       ip_hash;  # パーシステンス機能(IPアドレスに基づくセッションアフィニティ)
        server localhost:8001;  # バックエンドサーバ1
        server localhost:8002;  # バックエンドサーバ2
    }

再度この設定をNginxに反映させるために再起動する。

.\nginx.exe -s reload

すると、ブラウザからアクセスし、リロードボタンを何度押しても、同じサーバに接続される。

最後に

Apache・NginxやWEBサーバ、ロードバランサーの違いが理解できたと思います。
実際に動かしてみることでロードバランサー機能、パーシステンス機能も理解が深まりました!

しかし、また新たな疑問としてWEBサーバとアプリケーションサーバ、リバースプロキシサーバの違いも出てきたので、それらも今後調べていこうと思います!

こういった基礎的な用語をしっかり理解しておかないと、チームで開発していく際のずれの要因になってしまうと考えているので、こういった基盤はしっかりと築き上げていきたいです!

私の間違いなどございましたら、ご指摘していただけると嬉しいです。
ブログも初心者のため、「この辺りが見にくい」「構成はこうした方が良い」などございましたら、ご教示していただけると幸いです。

最後まで読んでいただき、ありがとうございました!

参考元

Discussion