ロードバランサーとは?負荷分散の仕組みと導入パターンを初心者向けに解説

kento_morota 14分で読めます

「サーバーが1台だけだと不安」「アクセスが集中するとサイトが落ちる」——サービスが成長するにつれて、多くのエンジニアがこうした課題に直面します。

ロードバランサー(負荷分散装置)は、複数のサーバーにトラフィックを分散することで、可用性とパフォーマンスを向上させる仕組みです。本記事では、ロードバランサーの基本概念から具体的な設定方法まで、初心者にもわかりやすく解説します。

ロードバランサーとは何か

ロードバランサーは、クライアントからのリクエストを複数のバックエンドサーバーに振り分ける役割を持つコンポーネントです。

ロードバランサーがない場合の問題

サーバーが1台だけの構成では、以下の問題が発生します。

単一障害点(SPOF)
そのサーバーが停止すると、サービス全体が利用不能になります。ハードウェア故障、ソフトウェアのバグ、メンテナンスなど、停止の原因は多岐にわたります。

スケーラビリティの限界
1台のサーバーで処理できるリクエスト数には上限があります。アクセスが増加すると、レスポンス時間が悪化し、最終的にはサーバーダウンにつながります。

メンテナンスの困難さ
サーバーのアップデートやアプリケーションのデプロイ時に、サービスを一時停止する必要があります。

ロードバランサー導入のメリット

高可用性
バックエンドサーバーの1台が停止しても、他のサーバーがリクエストを処理し続けるため、サービスは継続します。

水平スケーリング
サーバーを追加するだけで処理能力を増強できます。1台のサーバーを高性能にする「垂直スケーリング」にはコスト的な限界がありますが、水平スケーリングは柔軟に対応できます。

ゼロダウンタイムデプロイ
ローリングデプロイ(サーバーを1台ずつ更新)により、サービスを停止せずにアプリケーションを更新できます。

L4とL7ロードバランサーの違い

ロードバランサーは、OSI参照モデルのどのレイヤーで動作するかによって、L4(レイヤー4)とL7(レイヤー7)に分類されます。

L4ロードバランサー(トランスポート層)

IPアドレスとポート番号に基づいてトラフィックを振り分けます。パケットの中身(HTTPヘッダーやURL)は確認しません。

特徴

・高速な処理(パケット内容を解析しないため)
・プロトコルに依存しない(HTTP以外の通信にも対応)
・URLやCookieによる振り分けは不可
・TCP/UDP レベルでの分散

用途:データベースの負荷分散、TCPベースのサービス、高スループットが求められる場面。

L7ロードバランサー(アプリケーション層)

HTTPヘッダー、URL、Cookie、リクエストボディなどの情報に基づいて、より高度な振り分けが可能です。

特徴

・URLパスやホスト名による振り分け(パスベースルーティング)
・HTTPヘッダーやCookieによるセッション維持
・SSL/TLS終端処理(SSLオフロード)
・コンテンツに応じたキャッシュやレスポンスの書き換え

用途:Webアプリケーション、API、マイクロサービスのルーティング。

# L7ロードバランサーによるパスベースルーティングの例
/api/*       → APIサーバー群
/static/*    → 静的ファイルサーバー群
/admin/*     → 管理画面サーバー
/            → Webアプリサーバー群

負荷分散アルゴリズムの種類

ロードバランサーがどのサーバーにリクエストを振り分けるかは、分散アルゴリズムによって決まります。

ラウンドロビン

リクエストを順番に各サーバーへ振り分けます。最もシンプルなアルゴリズムです。

// ラウンドロビンのイメージ
リクエスト1 → サーバーA
リクエスト2 → サーバーB
リクエスト3 → サーバーC
リクエスト4 → サーバーA  // 最初に戻る
リクエスト5 → サーバーB
...

すべてのサーバーが同等の性能を持つ場合に適しています。性能差がある場合は、重み付きラウンドロビンを使用します。

重み付きラウンドロビン

各サーバーに重み(Weight)を設定し、性能に応じてリクエストの比率を変えます。

// 重み付きラウンドロビン(A:3, B:2, C:1の場合)
リクエスト1 → サーバーA
リクエスト2 → サーバーA
リクエスト3 → サーバーA
リクエスト4 → サーバーB
リクエスト5 → サーバーB
リクエスト6 → サーバーC
// サーバーAが50%、Bが33%、Cが17%のリクエストを処理

最小接続数(Least Connections)

現在の接続数が最も少ないサーバーにリクエストを振り分けます。処理時間にばらつきがある場合に効果的です。

// 最小接続数のイメージ
サーバーA: 現在の接続数 5
サーバーB: 現在の接続数 2  ← 次のリクエストはここに振り分け
サーバーC: 現在の接続数 8

IPハッシュ

クライアントのIPアドレスからハッシュ値を計算し、常に同じサーバーに振り分けます。セッション維持が必要な場合に使用しますが、セッションのサーバー側管理(後述)が推奨されます。

ヘルスチェックの仕組み

ロードバランサーは、バックエンドサーバーの状態を定期的に確認(ヘルスチェック)し、正常なサーバーにのみリクエストを振り分けます。

ヘルスチェックの種類

アクティブヘルスチェック
ロードバランサーが定期的にバックエンドサーバーにリクエストを送信し、応答を確認します。

# Nginxでのアクティブヘルスチェック設定
upstream backend {
    zone backend 64k;

    server 192.168.1.10:3000;
    server 192.168.1.11:3000;
    server 192.168.1.12:3000;
}

server {
    location /api/ {
        proxy_pass http://backend;

        # ヘルスチェック関連の設定
        proxy_connect_timeout 5s;
        proxy_read_timeout 10s;
        proxy_next_upstream error timeout http_500 http_502 http_503;
        proxy_next_upstream_tries 3;
    }
}

パッシブヘルスチェック
実際のリクエストの結果に基づいてサーバーの状態を判定します。エラーが連続した場合にサーバーを異常と判断します。

# Nginxでのパッシブヘルスチェック設定
upstream backend {
    server 192.168.1.10:3000 max_fails=3 fail_timeout=30s;
    server 192.168.1.11:3000 max_fails=3 fail_timeout=30s;
    server 192.168.1.12:3000 max_fails=3 fail_timeout=30s;
    # 3回連続で失敗すると30秒間そのサーバーを除外
}

アプリケーション側のヘルスチェックエンドポイント

// Node.js(Express)でのヘルスチェックエンドポイント
app.get('/health', async (req, res) => {
  try {
    // データベース接続の確認
    await db.query('SELECT 1');

    // Redisの接続確認
    await redis.ping();

    res.status(200).json({
      status: 'healthy',
      timestamp: new Date().toISOString(),
      checks: {
        database: 'ok',
        redis: 'ok',
      },
    });
  } catch (error) {
    res.status(503).json({
      status: 'unhealthy',
      timestamp: new Date().toISOString(),
      error: error.message,
    });
  }
});

セッション管理とスティッキーセッション

ロードバランサーを導入すると、同じユーザーのリクエストが異なるサーバーに振り分けられる可能性があります。セッション管理の方法を検討する必要があります。

スティッキーセッション

同じユーザーのリクエストを常に同じサーバーに振り分ける方式です。

# NginxでのCookieベーススティッキーセッション
upstream backend {
    ip_hash;  # IPアドレスベースのスティッキーセッション

    server 192.168.1.10:3000;
    server 192.168.1.11:3000;
    server 192.168.1.12:3000;
}

スティッキーセッションの問題点

・サーバーが停止するとそのサーバーのセッションが失われる
・負荷が均等に分散されない可能性がある
・サーバーの追加・削除時にセッションが再配置される

外部セッションストアの活用(推奨)

セッション情報をサーバーのメモリではなく、外部のデータストア(Redis、Memcached等)に保存する方式です。

// Node.js(Express)でのRedisセッションストア
const session = require('express-session');
const RedisStore = require('connect-redis').default;
const redis = require('redis');

const redisClient = redis.createClient({
  host: 'redis.example.com',
  port: 6379,
});

app.use(session({
  store: new RedisStore({ client: redisClient }),
  secret: 'your-secret-key',
  resave: false,
  saveUninitialized: false,
  cookie: {
    secure: true,
    httpOnly: true,
    maxAge: 3600000, // 1時間
  },
}));

// どのサーバーにリクエストが振り分けられても
// 同じセッション情報にアクセスできる

外部セッションストアを使えば、スティッキーセッションが不要になり、負荷を均等に分散できます。

主要なロードバランサーの設定例

実際に使用される主要なロードバランサーの設定方法を紹介します。

Nginxでのロードバランシング

# /etc/nginx/nginx.conf
http {
    upstream api_servers {
        least_conn;  # 最小接続数アルゴリズム

        server 192.168.1.10:3000 weight=3;
        server 192.168.1.11:3000 weight=2;
        server 192.168.1.12:3000 weight=1;
        server 192.168.1.13:3000 backup;  # バックアップサーバー
    }

    server {
        listen 443 ssl http2;
        server_name api.example.com;

        ssl_certificate /etc/ssl/certs/api.example.com.pem;
        ssl_certificate_key /etc/ssl/private/api.example.com.key;

        location / {
            proxy_pass http://api_servers;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            # タイムアウト設定
            proxy_connect_timeout 5s;
            proxy_send_timeout 60s;
            proxy_read_timeout 60s;
        }
    }
}

AWS ALB(Application Load Balancer)

// AWS CDK(TypeScript)でのALB設定例
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import * as ec2 from 'aws-cdk-lib/aws-ec2';

// ALBの作成
const alb = new elbv2.ApplicationLoadBalancer(this, 'ALB', {
  vpc,
  internetFacing: true,
});

// ターゲットグループの作成
const targetGroup = new elbv2.ApplicationTargetGroup(this, 'TargetGroup', {
  vpc,
  port: 3000,
  protocol: elbv2.ApplicationProtocol.HTTP,
  targetType: elbv2.TargetType.INSTANCE,
  healthCheck: {
    path: '/health',
    interval: cdk.Duration.seconds(30),
    timeout: cdk.Duration.seconds(5),
    healthyThresholdCount: 2,
    unhealthyThresholdCount: 3,
  },
});

// リスナーの追加
const listener = alb.addListener('Listener', {
  port: 443,
  certificates: [certificate],
});

listener.addTargetGroups('DefaultTarget', {
  targetGroups: [targetGroup],
});

// パスベースルーティング
listener.addAction('APIRoute', {
  priority: 10,
  conditions: [elbv2.ListenerCondition.pathPatterns(['/api/*'])],
  action: elbv2.ListenerAction.forward([apiTargetGroup]),
});

まとめ:適切なロードバランサー構成を選ぼう

ロードバランサーは、サービスの信頼性とスケーラビリティを確保するために不可欠なコンポーネントです。

本記事のポイントを整理します。

基本概念
・ロードバランサーは複数サーバーにトラフィックを分散する
・単一障害点の排除、水平スケーリング、ゼロダウンタイムデプロイを実現する

L4とL7の使い分け
・L4は高速で汎用的、L7は高度なルーティングが可能
・WebアプリケーションではL7(HTTP)ロードバランサーが一般的

分散アルゴリズム
・ラウンドロビン:シンプルで均等な分散
・最小接続数:処理時間にばらつきがある場合に有効
・IPハッシュ:セッション維持に使えるが、外部セッションストアが推奨

運用のポイント
・ヘルスチェックを必ず設定し、異常なサーバーを自動排除する
・セッション管理はRedisなどの外部ストアを活用する
・X-Forwarded-Forなどのヘッダーでクライアントの実IPを保持する

小規模なサービスでも、ロードバランサーの導入は可用性の向上に大きく貢献します。サービスの成長に備えて、早い段階からロードバランサーを見据えたアーキテクチャを設計しておくことを推奨します。

#ロードバランサー#負荷分散#インフラ
共有:
無料メルマガ

週1回、最新の技術記事をお届け

AI・クラウド・開発の最新記事を毎週月曜にメールでお届けします。登録は無料、いつでも解除できます。

プライバシーポリシーに基づき管理します

起業準備に役立つ情報、もっとありますよ。

まずは話だけ聞いてもらう