Skip to content

ユーザー名ごとのセッションクォータ

このプラグインは、ユーザー名ごとのセッションクォータを強制します。

  • セッションカウンターはユーザー名ごとに管理され、クラスター全体で同期されます。
  • 設定されたクォータに達すると、認証は quota_exceeded で拒否されます。
  • 既存の clientid での再接続は追加のクォータを消費しません。
  • ユーザー名ごとのクォータオーバーライドにより、カスタム制限、無制限セッション、または接続ブロックが可能です。

注意

デプロイメントで client_attrs_init 設定の client_attrs.tns を設定してユーザー名をネームスペースとして使用できる場合は、ネームスペースベースの制限を通じてこの種のセッション制限を強制できます。 ネームスペースの割り当てが異なるスキームに従う場合のみ、このプラグインを使用してください。

設定

フィールドデフォルトバリデーション説明
max_sessions_per_username100正の整数(>= 1)でなければなりません。1未満または非数値は拒否されます。ユーザー名ごとのデフォルト最大同時セッション数。個別のユーザー名はオーバーライドAPIでこの値を上書き可能です。
snapshot_min_age_ms300000120000 から 900000 の範囲内でなければなりません。範囲外の値はクランプされます。スナップショットの最小有効期間(ミリ秒)。これにより大規模クラスターでの頻繁な再構築を防ぎます。
snapshot_request_timeout_ms5000正の整数に変換可能な文字列も受け入れます。リストAPIのスナップショット要求処理のタイムアウト時間(ミリ秒)。

プラグイン設定は標準のプラグイン設定APIで更新します:

PUT /api/v5/plugins/<name-vsn>/config

ランタイムAPI

プラグインはプラグインAPIゲートウェイを通じてランタイムAPIを公開します。

ベースパス:/api/v5/plugin_api/emqx_username_quota

セッションクエリ

  • GET /quota/usernames: アクティブなセッションを持つすべてのユーザー名を一覧表示します。
  • GET /quota/usernames/:username: 単一ユーザー名の詳細を取得します。
  • GET /metrics: プラグインのメトリクスをPrometheusテキスト形式でエクスポートします。
  • POST /kick/:username: 指定ユーザー名のすべてのセッションをキックします。

スナップショット管理

  • DELETE /quota/snapshot: スナップショットの再構築を強制します。

クォータオーバーライド

  • POST /quota/overrides: ユーザー名ごとのクォータオーバーライドを設定します。
  • DELETE /quota/overrides: ユーザー名ごとのクォータオーバーライドを削除します。
  • GET /quota/overrides: すべてのクォータオーバーライドを一覧表示します。

GET /quota/usernames

このエンドポイントは、毎回ライブのセッションデータをスキャンする代わりに、事前に構築されたスナップショットから結果を返します。

スナップショットは、ユーザー名ごとのセッション数の時点コピーであり、効率的なカーソルベースのページネーションのためにセッション数でソートされています。スナップショットは非同期にバックグラウンドで構築されキャッシュされます。現在のスナップショットが snapshot_min_age_ms より古い場合にのみ新しい構築がトリガーされます。

最初のリクエスト到着時にスナップショットが存在しない場合、サーバーは進行中の構築完了を待ちます。待機時間はリクエストのデッドラインから1秒引いた時間までです。構築が間に合えば通常の 200 レスポンスを返します。間に合わなければ 503 と部分データを返します。

クエリパラメータ:

  • limit: 正の整数、最大100(デフォルト100)
  • used_gte: カーソルがない場合は必須。これは最小セッション数フィルターです。この数以上のセッションを持つユーザー名のみが含まれます。正の整数 >= 1 でなければなりません。
  • cursor: 以前のリスト呼び出しで返された不透明なカーソル。省略すると最初のページが返されます。

パラメータルール:

  • used_gte のみ(cursorなし):OK(最初のページ)
  • cursor のみ(used_gteなし):OK(used_gte はカーソルに埋め込まれています)
  • used_gtecursor 両方:400 BAD_REQUEST。フィルターはカーソルに固定されています。
  • used_gtecursor もなし:400 BAD_REQUEST

動作:

  • 結果は常にセッション数、次いでユーザー名でソートされます。
  • ページネーションはカーソルベースです。最初のページは cursor を省略してください。
  • 各アイテムには username、リアルタイムの used、および limit(有効なクォータ)が含まれます。
  • リアルタイムの used がスナップショットのカウントと異なる場合、キャッシュされたカウントと現在のカウントの両方を確認できるように snapshot_used が含まれます。

成功レスポンスの構造:

  • data: ユーザー名クォータエントリ
  • meta.limit: ページサイズ(ページネーション制限)
  • meta.count: このページのエントリ数
  • meta.total: スナップショット内の総エントリ数
  • meta.next_cursor: 次ページ用カーソル(存在する場合)
  • meta.snapshot: スナップショットメタデータ:
    • node
    • generation(インクリメンタルスナップショットID)
    • taken_at_ms(スナップショット取得時刻(ミリ秒))

エラー応答:

  • 400 BAD_REQUEST: used_gte がない、または used_gtecursor が両方指定された場合
  • 400 INVALID_CURSOR: カーソルが利用できないノードを参照しているか不正な形式
  • 503 SERVICE_UNAVAILABLE: スナップショットが再構築中
    • ボディに snapshot_build_in_progress: truedatameta を含む
    • data: 進行中のスナップショットから読み取った部分的な最初のページ(構築開始直後の場合は空の場合あり)
    • meta.count: 部分的なエントリ数、meta.partial: true
    • バウンデッドバックオフで同じリクエストを再試行してください

DELETE /quota/snapshot

即時にスナップショットの再構築を強制します。非同期に再構築を開始した後、{"status": "ok"} を含む 200 を返します。スナップショットはバックグラウンドで再構築されます。

GET /quota/usernames/:username

単一ユーザー名の詳細を返します。レスポンスフィールドは usernameusedlimitclientids です。

ユーザー名にアクティブなセッションがない場合は 404 NOT_FOUND を返します。

GET /metrics

プラグインのPrometheusテキスト形式メトリクスを返します。 レプリカントノードではリクエストがスナップショット所有コアノードに転送されます。

現在エクスポートされているメトリクス:

  • emqx_username_count: アクティブスナップショット内のユーザー名総数

POST /kick/:username

指定ユーザー名のすべてのセッションをキックします。キックしたセッション数Nを含む {"kicked": N} を返します。

ユーザー名にアクティブなセッションがない場合は 404 NOT_FOUND を返します。

POST /quota/overrides

ユーザー名ごとのクォータオーバーライドを設定します。ボディはJSON配列です:

json
[
  {"username": "user1", "quota": 1000},
  {"username": "vip", "quota": "nolimit"},
  {"username": "blocked", "quota": 0}
]

オーバーライドの意味:

quota の値意味
正の整数このユーザー名のカスタムセッション制限
"nolimit"無制限セッション(クォータ制限なし)
0接続禁止:新規接続をすべて拒否

オーバーライドはディスクに永続化され、クラスター全体にレプリケートされます。ユーザー名にオーバーライドがない場合は、グローバル設定の max_sessions_per_username が使用されます。

DELETE /quota/overrides

ユーザー名によるオーバーライドを削除します。ボディはユーザー名文字列のJSON配列です:

json
["user1", "blocked"]

GET /quota/overrides

すべてのオーバーライドを一覧表示します。{"data": [{"username": "...", "quota": ...}, ...]} を返します。

スナップショットベースの一覧表示の仕組み

このセクションでは、GET /quota/usernamesGET /metrics のようなリスト形式APIのためにプラグインがスナップショットをどのように構築し提供するかを説明します。

スナップショット所有者ルーティング

スナップショットはコアノードで構築されます。GET /quota/usernamesGET /metrics は、ソートされた稼働中のコアノードリストの最初のノードとして選ばれたスナップショット所有コアノードにルーティングされます。

ブルー/グリーンスナップショット

2つのスナップショットバッファ(ブルーとグリーン)を維持します。1つは読み取り要求に応答し、もう1つは次のスナップショット構築に使用されます。構築完了後に役割を入れ替えます。これにより、再構築中も古いスナップショットが利用可能なため、データギャップが発生しません。

バックグラウンドスナップショット構築

スナップショットの再構築はバックグラウンドプロセスで実行され、サーバーをブロックしないようにイールドベースのスロットリングが行われます。構築中もリストAPIは応答可能です。

運用上の考慮事項と制限

このセクションでは、本プラグインを本番環境で運用する際のランタイム挙動や制限事項を説明します。

接続バースト時のクォータ超過

クォータの判定は認証時に行われ、セッションカウンターの確定はセッションライフサイクルフックで行われます。高い同時接続バースト(特にクラスター環境)下では、1ユーザー名の同時セッション数が一時的に max_sessions_per_username を超える短い同期ウィンドウが発生します。

実務上の意味:

  • 本プラグインはクラスター全体でのクォータ強制を提供しますが、バースト負荷下では最終的整合性を保証します。
  • 極端な接続集中時においては、常に厳密な接続単位のクォータ強制は保証されません。

プラグイン起動時のブートストラップ動作

プラグインを稼働中のクラスターにインストールした場合、既存のクライアントセッションはフック登録前に確立されています。起動時に、プラグインはローカルのすべてのチャネルを巡回してセッションを登録し、クォータ状態をブートストラップします。

コアノードへのDB書き込み負荷集中を避けるため(特にレプリカントノードに多数の既存接続がある場合)、ブートストラップループはスロットリングされます:

  • セッションは100件ずつバッチ登録されます。
  • 各バッチ後、最後に書き込まれたレコードがローカルテーブルにレプリケートされるのを待ちます。ポーリング間隔は10msです。
  • 10秒以内にレプリケーションが完了しない場合、エラーをログに記録し、error レベルログとともにブートストラップを中止します。 タイムアウト前に登録されたセッションは保持され、残りは再接続時のフック登録で自然に拾われます。

リストAPIの 503 応答の取り扱い

サーバーがビジー状態かスナップショット構築中の場合、リストAPIは 503 を返します。

503 のレスポンスボディには、進行中のスナップショットテーブルから読み取った部分的な最初のページを含む data 配列が含まれます。これにより呼び出し元は空の応答ではなく即時にベストエフォートのデータを受け取れます。meta.partial: true フラグはデータが不完全であることを示します。構築開始直後の場合は部分ページが空の場合もあります。

APIクライアントへのガイダンス:

  • 即時に利用可能な部分結果があれば data を確認してください。
  • バウンデッドバックオフで再試行してください。

ダウンロード

各EMQXリリース用のtarball:

EMQXバージョンプラグインバージョンパッケージ
6.1.11.0.0emqx_username_quota-1.0.0.tar.gz
6.1.21.2.1emqx_username_quota-1.2.1.tar.gz
6.1.31.2.2emqx_username_quota-1.2.2.tar.gz