Chuyển đến nội dung chính

レッスン 10: レート制限とスロットリング — 送信速度の制御

電子メール システムにレート制限が必要な理由。トークンバケツ、引き違い窓、漏れやすいバケツ。プロバイダー、ドメイン、IP によるマルチレベルのスロットル。適応レート制限は直帰率に基づいています。 Redis ベースの分散リミッター。

🏗️ アーキテクチャ — レッスン 10 レッスン 10: レート制限とスロットリング — チェック 送信速度の制御

数百万の電子メールを送信する通知システムを設計する

パート 4: スケールの処理 — 数百万までのスケーリング

xdev.asia

はじめに

数百万もの電子メールをレンダリングしてキューに入れることができるシステムは、電子メールを安全に送信できない可能性があります。本当のボトルネックは多くの場合、有効な送信速度、つまり ESP、ドメイン/IP レピュテーション、およびダウンストリーム システムの吸収容量による制限にあります。

この記事では、1,000 万件の電子メール キャンペーンが成功するか、ドメイン全体がスパム フォルダーに移動されるかを決定するトラフィック規制レイヤーに焦点を当てます。


1. レート制限が必要なのはなぜですか?

実際の制限

限られたソース例しきい値を超えた場合の結果
ESP 送信クォータSES デフォルト 200 メール/秒ThrottlingException、キューのバックログ
ドメインの評判新しいドメインから突然 100 万件のメールが送信されましたスパムの掲載が急増
IP の評判専用 IP はまだウォームアップされていませんバウンスと苦情が増加
ISP の制限Gmail、Yahoo のドメインによるスロットリング遅延配信、ソフト バウンス
内部システムワーカーが多すぎる、DB 更新が厚すぎるCPU 使用率が高い、ロック競合

スロットル層の目標

  • 送信者の評判を保護します。
  • 電子メールプロバイダーをトラフィックバーストから保護します。
  • マーケティング電子メールよりもトランザクション電子メールを優先します。
  • 短いスパイクが発生してクラッシュするのではなく、安定したスループットを維持します。
  • キューのバックログを管理下に置きます。

2. 一般的なアルゴリズム

簡単な比較

アルゴリズム強み弱点に適しています
固定ウィンドウ実装が簡単ウィンドウ境界でバーストシンプルカウンター
スライディングウィンドウより正確により多くの状態を消費しますドメインごとの制限
漏れやすいバケツ出力は等しい有効なトラフィックバーストではやや硬い交通をスムーズにする
トークンバケット制御されたバーストを許可します。状態を同期する必要がありますESP/API スロットル

電子メール システムに関する推奨事項

  • トークン バケットを使用して、プロバイダーおよび IP プールごとに制限します。
  • キャンペーン/ドメインごとの苦情率、直帰率、開封率には スライディング ウィンドウ を使用します。
  • 優先度を意識したスケジューラを使用して、重要な電子メールがマーケティングに消費されるのを防ぎます。

3. マルチレベルのスロットリングアーキテクチャ

Campaign Queue
    │
    ▼
Priority Scheduler
    │
    ├── Check provider quota (SES / SendGrid / Mailgun)
    ├── Check domain quota (gmail.com / yahoo.com / outlook.com)
    ├── Check IP pool quota
    ├── Check campaign quota
    └── Check suppression / reputation guard
    │
    ▼
Dispatch Queue
    │
    ▼
Workers -> ESP

合理的なテスト順序

  1. サプレッションリストとバウンス履歴を確認します。
  2. メッセージの優先度クラスを確認します。
  3. プロバイダーごとのクォータを確認します。
  4. 受信者ドメインごとにクォータを確認します。
  5. 送信者 IP / 専用 IP プールに応じてクォータを確認します。
  6. 失敗した場合は、ドロップするのではなく、再スケジュールします。

優先ポリシーの例

優先事項使用例SLAルール
クリティカルOTP、パスワードをリセット< 30 代常に予約容量が存在します。
高い注文確認< 2 分マーケティングによってブロックされていない
通常製品のアップデート15 分未満動的なクォータ共有
低いニュースレター、点滴キャンペーンスケジュール通り悪評が出る前に打ち切り

4. Redis を使用した分散レート リミッター

Token bucket model

import time
import redis

class RedisTokenBucket:
    def __init__(self, client: redis.Redis, key: str, rate: int, burst: int):
        self.client = client
        self.key = key
        self.rate = rate
        self.burst = burst

    def allow(self, tokens: int = 1) -> ブール:
        now_ms = int(time.time() * 1000)
        スクリプト = """
        ローカルキー = KEYS[1]
        ローカルの now_ms = tonumber(ARGV[1])
        ローカル レート = tonumber(ARGV[2])
        ローカル バースト = tonumber(ARGV[3])
        ローカル要求 = tonumber(ARGV[4])

        ローカルデータ = redis.call('HMGET', キー, 'トークン', 'updated_at')
        ローカルトークン = tonumber(data[1])
        ローカルの updated_at = tonumber(data[2])

        トークン == nil の場合
          トークン = バースト
          updated_at = now_ms
        終わり

        ローカル経過 = math.max(0, now_ms - updated_at)
        ローカル補充 = (経過 / 1000.0) * レート
        トークン = math.min(バースト, トークン + リフィル)

        ローカルで許可 = 0
        トークン >= 要求された場合
          トークン = トークン - 要求された
          許可 = 1
        終わり

        redis.call('HMSET', キー, 'トークン', トークン, 'updated_at', now_ms)
        redis.call('PEXPIRE', キー, 60000)
        返品可能
        「」

        result = self.client.eval(script, 1, self.key, now_ms, self.rate, self.burst, トークン)
        戻り結果 == 1

従うべき鍵

レート:プロバイダー:ses
レート:プロバイダー:sendgrid
料金:ドメイン:gmail.com
料金:ドメイン:yahoo.com
レート:IP プール:warm-01
料金:キャンペーン:camp_flash_sale_april

重要な点は、リミッターは すべてのワーカー間で共有される必要があるということです。そうしないと、各ワーカーは自分には割り当てがあると思い込み、システムはすぐに制限を超えてしまいます。


5. 信号到達性に基づく適応型スロットリング

送信速度は固定すべきではありません。現実からの信号に反応する必要があります。

監視する信号

信号意味アクション
ソフトバウンスが増加しますISP はトラフィックを遅延します送信レートが 20 ~ 40% オフ
苦情率の増加コンテンツ/リストの品質が悪い大幅削減、キャンペーン一時停止
開封率が異常に低下スパムの掲載が増加速度を下げ、IP/ドメインの組み合わせを変更する
キューの遅延が大きすぎますシステムにワーカー/クォータがありません従業員を増やすかETAを延長する

ポリシーエンジンの例

def compute_send_rate(base_rate, メトリクス):
    レート = 基本レート

    metrics.soft_bounce_rate > 0.03の場合:
        率 *= 0.7

    metrics.complaint_rate > 0.001の場合:
        率 *= 0.5

    metrics.provider_throttling_rate > 0.05の場合:
        率 *= 0.8

    metrics.critical_queue_ Depth > 1000の場合:
        レート = 最大(レート, metrics.reserve_for_critical)

    戻り値 max(int(rate), 10)

原則

  • マーケティング トラフィックは最初に犠牲になる場所です。
  • トランザクション トラフィックには固定クォータ予約が必要です。
  • 苦情の急増が非常に高いか、ESP の一時停止が必要な場合を除き、クォータをすぐに 0 に減らさないでください。

6. IP ウォーミングとドメインのウォームアップ

よくある間違いは、新しいドメイン/IP を使用したにもかかわらず、初日にフルロードを送信してしまうことです。

新しい専用 IP のウォームアップ ロードマップのサンプル

日付1 日あたりの最大メール数オブジェクト
15,000ユーザーの関与度は高い
210,000セグメントはクリーン、最近アクティブ
320,000わずかな拡張
440,000混合トラフィックを開始する
580,000苦情/返送に対応する
6160,000スケーリングを続行
7+評判によるとメトリクスに問題がない場合にのみ増加します

ウォームアップ中のガードレール

  • 明確にオプトインした受信者にのみ送信します。
  • 開封率/クリック率が高いセグメントを優先します。
  • 古い低品質のリストを再利用しないでください。
  • 利用可能な場合は、Gmail ポストマスター ツールと Microsoft SNDS を監視します。

7. 一般的な故障モード

リミッターの設計が間違っている場合

  1. ワーカーごとのローカル リミッター: 各ワーカーが「正しい」場合でも、合計スループットがクォータを超えます。
  2. 予備容量なし: マーケティング キャンペーンがすべてのトークンを消費しているため、OTP が遅くなります。
  3. プロバイダーに従って調整するが、ドメインを忘れた: ESP は引き続き受信しますが、Gmail は遅延を開始します。
  4. 無限再試行: 再試行の嵐によりスロットルが増幅されます。

チェックリストの作成

  • プロバイダー、ドメイン、IP、キャンペーンごとに割り当てがあります。
  • クリティカルなトラフィック用に予備を備えています。
  • 手動一時停止キャンペーンのメカニズムがあります。
  • フィードバック ループに基づいた適応スロットリングを備えています。
  • 現在の送信速度と残りのクォータを表示するダッシュボードがあります。

概要

レート制限は単なる技術的な問題ではなく、到達性を保護するための重要な層です。優れたシステムは、許可されている場合は迅速に送信し、信号が悪い場合は速度を落とし、最も重要なトラフィックを常に優先する方法を知っている必要があります。

次の記事: バッチ処理とワーカー プールを編成して、メモリ不足やデータベースの詰まりを発生させずに数百万の受信者を効率的に処理できるようにします。