[Apache]スロットリング

Apache2には特定の条件に基づいて通信帯域を制限(スロットリング)する機能が備わっています。

「特定のユーザ」をどのように定義するか(IPアドレス、認証済みのユーザ名、あるいは特定のヘッダを持っているか)によっていくつか方法がありますが、現在最も標準的で扱いやすいのは mod_ratelimit モジュールを使用する方法です。

1. mod_ratelimit を使用する方法

このモジュールは、環境変数 rate-limit が設定されている場合に、そのリクエストの転送速度を制限します。

ステップ1: モジュールの有効化

まずはモジュールを有効にしてApacheを再起動します。

sudo a2enmod ratelimit
sudo systemctl restart apache2

ステップ2: 特定のユーザを識別して制限をかける

SetEnvIfRewriteRule を組み合わせて、条件に一致した時だけ環境変数をセットします。

パターンA:特定のIPアドレスを制限する場合

# 192.168.1.100 からのアクセスを 500KB/s に制限
SetEnvIf Remote_Addr "192.168.1.100" rate-limit=500

パターンB:Basic認証の特定のユーザ名を制限する場合

# ユーザ名 "guest_user" の場合のみ 100KB/s に制限
SetEnvIf Remote_User "guest_user" rate-limit=100

パターンC:特定のUser-Agent(特定のブラウザやBot)を制限する場合

# 特定のBotからのアクセスを 50KB/s に制限
SetEnvIf User-Agent "BadBot" rate-limit=50

2. もっと細かく制御したい場合 (mod_bw)

mod_ratelimit はシンプルですが、複雑な制御(合計帯域の制限や、同時接続数に応じた動的な制限など)には不向きです。より高度な設定が必要な場合は mod_bw(Bandwidth Mod)という外部モジュールを使う伝統的な手法もありますが、設定がやや複雑になります。

3. アプリケーション層(PHP)で制御する場合

もし「特定のユーザ」の判定ロジックがデータベースに依存していたり、もっと柔軟に(例:FXツールのプレミアム会員は無制限、無料会員は制限など)制御したい場合は、Apacheではなく PHP側で読み込み速度をコントロール するのも一つの手です。

// 簡易的なスロットリング例
public function download($request, $response) {
    $file = 'path/to/large_file.zip';
    $speed = 100; // KB/s

    $stream = fopen($file, 'rb');
    while (!feof($stream)) {
        echo fread($stream, $speed * 1024);
        flush();
        sleep(1); // 1秒待機して速度を調整
    }
}

💡 運用のヒント

  • 単位に注意: mod_ratelimit の数値は KiB/s です。
  • 測定方法: 制限が効いているか確認するには、クライアント側で wgetcurl を使ってダウンロード速度を表示させるのが確実です。Bashcurl -o /dev/null http://your-server.com/testfile
  • パフォーマンスへの影響: 大量の同時接続がある環境でPHP側でスロットリングを行うと、PHPのプロセス(Worker)を長時間占有してしまうため、基本的には Apache(mod_ratelimit)で行うのが最も効率的 です。

コメント

タイトルとURLをコピーしました