Artifact Registry ADR 004: データおよびアプリケーションの上限
背景
Artifact Registry は、システム安定性を確保し、不正利用を防ぎ、予測可能なリソース消費を可能にするため、明示的な上限を定義する必要があります。これらの上限は、データの保持期間を管理するデータ保持ポリシー(ADR-010 を参照)とは異なります。ここでの上限は、任意の時点でどれだけのデータと操作が許可されるかを管理します。
定義された上限がなければ、少数のテナントが不釣り合いなリソースを消費し、すべての顧客のサービス品質を劣化させる可能性があります。CI/CD ワークロードは非常にスパイクのあるトラフィックを生み出します(ADR-003 を参照)。バースト制御は特に重要です。
本 ADR では、3 つのタイプの制約を区別します。
- 上限 (Limits) はアプリケーションの安定性とセキュリティを保護します。リクエスト単位または時間ウィンドウ単位で強制され、ビリングには紐づきません。例: アーティファクトアップロードの最大サイズ、API レート上限、エンティティ数のキャップ。
- クォータ (Quotas) は請求サイクルやプランに紐づく総消費の制約です。namespace が全体としてどれだけリソースを消費できるかを管理します。例: namespace あたりのストレージクォータ。
- ポリシー (Policies) は、Artifact Registry へのアクセスを制御する、アプリケーションコードから切り離されたビジネスロジックを表します。ポリシーは上限とクォータの前に評価されます。
- 例: Organization の IP 許可リストにない IP からのアクセスを拒否
- 例: ブロックまたは禁止されたユーザーのアクセスを拒否
本 ADR では、上限(アーティファクトサイズ、API レート、エンティティ数)と クォータ(ストレージ)を扱います。
Artifact Registry は GitLab.com 規模をターゲットとします: 定常状態で毎秒数千の API リクエスト、合計数十ペタバイトのデータ、大規模 Organization あたり数百万のアーティファクト(ADR-003 を参照)。上限は正当なエンタープライズワークロードを支えるのに十分高く、かつ単一の namespace がサービスを不安定にしないように低くする必要があります。
該当する場合、上限はパッケージレジストリとコンテナレジストリで既に確立されたものと整合または拡張し、GitLab レジストリ全体で一貫した体験を提供します。
決定
Artifact Registry は、Artifact Registry のテナンシーおよびパーティション境界である namespace レベルで、ストレージ(クォータ)、アーティファクトサイズ(上限)、API レート(上限)、エンティティ数(上限)の 4 つの次元にわたってクォータと上限を強制します。レート上限とストレージクォータのプランティアごとのデフォルトは、請求アンカー(Organization)から継承されますが、すべての上限は namespace ごとに強制および計測されます。複数の namespace を所有する Organization は、それらの namespace の利用量合計に対して請求されます。namespace をまたいだ重複排除やプーリングはありません。
アーティファクトサイズ上限とエンティティ数上限は、すべてのインストールタイプで同じデフォルトを使用します。レート上限は GitLab.com ではプラン依存です。各プランティアが独自のデフォルトレート上限を定義し、個別の namespace は正当な高負荷利用に対してカスタムオーバーライドを受け取れます。Self-Managed では、管理者がインスタンスレベルですべての上限を調整できます。
ストレージクォータ
ストレージクォータは namespace レベルで強制されます。ストレージは namespace 内のすべての一意な Blob の重複排除済み合計として計測されます。重複排除は ADR-002 と整合して namespace ごとにスコープされます。namespace をまたいだ重複排除はありません。複数の namespace を所有する Organization は、各 namespace のストレージ合計を消費し、その合計に対して請求されます。Organization は引き続き請求アンカーです(ADR-001)。
| クォータ | デフォルト | 注 |
|---|---|---|
| namespace あたり最大ストレージ | プラン依存(SKU ベース) | Artifact Registry は新しい premium SKU です(概要 を参照)。ストレージクォータは購入したアドオンによって定義されます |
| リポジトリあたり最大ストレージ | デフォルトでは厳格な制限なし | namespace レベルで構成可能なオプショナルな警告閾値。超過時に namespace オーナーに通知されますが、アップロードはブロックされません |
警告閾値(例: クォータの 80%)は namespace ごとに構成できます。利用がこの閾値を超えると、namespace オーナーに通知されますが、クォータに完全に達するまでアップロードはブロックされません。
新しいアップロードセッションを受け入れる前に、システムは namespace がストレージクォータに達しているか超過しているかを確認します。namespace にまだ余裕がある場合、アップロードは受け入れられ、利用カウンターは正常完了後に更新されます。namespace が既にクォータに達しているか超過している場合、アップロードセッションは拒否されます。
利用カウンターは正常アップロードごとに更新されるため、並行アップロードセッションはそれぞれ独立してクォータチェックを通過し、合計でクォータをわずかに超過する可能性があります。これは許容されます。厳密な強制はすべてのアップロードを直列化することを必要とし、ADR-003 の並行性目標と矛盾します。超過は並行アップロード数によって境界付けられ、次のクォータチェックで修正されます。
アーティファクトサイズ上限
アーティファクトサイズ上限はアーティファクトタイプによって異なります。以下のデフォルト値はすべてのインストールタイプに適用されます。Self-Managed では、管理者がインスタンスレベルでこれらのデフォルトをオーバーライドできます。
| アーティファクトタイプ | 最大アーティファクトサイズ | 注 |
|---|---|---|
| Maven | 5 GB | 既存のパッケージレジストリ上限と一致 |
| npm | 5 GB | 既存のパッケージレジストリ上限と一致 |
| コンテナイメージ | 50 GB | Blob あたりの最大サイズ。 |
加えて、コンテナイメージには次の上限が適用されます。
| 上限 | デフォルト | 注 |
|---|---|---|
| 最大マニフェストペイロード | 250 KB | Docker および OCI マニフェストに適用。 |
| 最大マニフェスト参照数 | 200 | マニフェストが参照できる Blob またはマニフェストの最大数 |
アップロードセッションには非アクティブタイムアウトが課されます。タイムアウトウィンドウ内にデータが受信されない場合、セッションは終了し、部分的にアップロードされたデータは破棄されます。これにより、Slowloris のような低速 DoS 攻撃を緩和し、アイドル状態のセッションがリソースを無期限に保持することを防ぎます。
レート上限
レート上限は API を不正利用から保護し、単一のユーザーまたは namespace が共有インフラを使い果たすのを防ぎます。レート上限違反は HTTP 429(Too Many Requests)と Retry-After ヘッダーを返します。
Self-Managed では、管理者がインスタンスレベルでレート上限のデフォルトをオーバーライドできます。
GitLab.com では、レート上限は最初はロギング/警告モードでデプロイされ、トラフィック分布が分析された後にのみ強制されます(ロールアウト戦略 を参照)。この段階的ロールアウトは、合理的なデフォルトを確立するための一回限りのプロセスです。Self-Managed では、管理者は直接レート上限を構成し強制できます。
IP ベースの上限
IP ベースのレート上限は、不正利用に対する最外層の防御を提供し、ロールアウト中に最初に導入される上限です(ロールアウト戦略 を参照)。これは コンテナレジストリの GCRA ベースのミドルウェア を再利用します。初期デフォルト値は、本番トラフィック分析に基づいて Observe フェーズ中に決定されます。
ユーザーごとの上限
ユーザーごとのレート上限はプラン依存です。Organization 内のユーザーは、その Organization のプランティアからデフォルトを継承します。プランごとのデフォルト値は、ユーザーごとのトラフィック分布に基づいて ロールアウト戦略 の Observe フェーズ中に決定されます。既存の パッケージレジストリレート上限 がベースライン参照として機能します。
Namespace ごとの上限
Namespace ごとのレート上限はプラン依存です。各プランティア(Premium、Ultimate)が独自のデフォルトレート上限を定義し、namespace の請求アンカーから継承されます。個別の namespace は構成のファーストクラスのプロパティとして独自のレート上限を持つことができ、例外単位で管理されるのではなく、同じプランのすべての namespace のデフォルトを引き上げずに正当な高負荷利用に対応します。プランごとのデフォルト値は、namespace ごとのトラフィック分布に基づいて ロールアウト戦略 の Observe フェーズ中に決定されます。
このティア分けされたアプローチは、単一のグローバルデフォルトの問題を回避します。重い正当ユーザー向けに 1 つの値を高く設定すると、残り全員にレート上限を実質的に無効にします。プランベースのデフォルトと namespace ごとのオーバーライドにより、プラットフォームは下位ティアでは不正利用から保護し、上位ティアでは大量利用顧客をサポートできます。
Namespace レベルの上限は、プラットフォームの主要な保護メカニズムです。ユーザーごとの上限は、単一のユーザーが namespace の全クォータを消費するのを防ぐための二次層を提供します。
並行アップロードセッション
並行アップロードセッション上限は、ユーザーあたりおよび namespace あたりの進行中アップロード数をキャップします。これにより、単一のアクターがアップロードインフラを独占するのを防ぎます。レート上限と同様、並行アップロードセッション上限はプラン依存です。プランごとのデフォルト値は ロールアウト戦略 の Observe フェーズ中に決定されます。
エンティティ数上限
エンティティ数上限は、API の振る舞い、プロキシチェーンの複雑さ、ポリシー評価コストに影響する特定の運用パラメータをキャップします。リポジトリ数は、自動化バグからのランナウェイ作成を防ぐため、namespace ごと、アーティファクトタイプごとにキャップされます。
| エンティティ | 上限 | 注 |
|---|---|---|
| namespace あたりアーティファクトタイプごとのリポジトリ数 | 1,000 | インスタンスレベルで構成可能 |
| アーティファクト/パッケージバージョンあたりのタグ数 | 1,000 | 不正利用と誤用を防止 |
| パッケージあたりのバージョン数 | 25,000 | 不正利用と誤用を防止 |
| 仮想リポジトリあたりのアップストリームソース数 | 20 | プロキシチェーンの複雑さを制限 |
| リポジトリあたりのライフサイクルポリシールール数 | 50 | ポリシー評価の複雑さを制限 |
アップストリームソースとライフサイクルポリシールールの上限は、書き込み時に同期的に強制されます。これらの上限を超えようとする試みは HTTP 422(Unprocessable Entity)を返します。
結果
ポジティブ
- システム安定性: 明示的な上限により、ランナウェイワークロードが共有インフラを不安定にするのを防ぐ
- 予測可能なパフォーマンス: 境界のあるポリシー評価とプロキシチェーンの複雑さにより、メタデータクエリがスケールでも高性能を保つ
- 明確な顧客期待値: 文書化された上限により、顧客は利用とキャパシティを計画できる
- 公平なマルチテナンシー: namespace スコープのレート上限、ストレージクォータ、エンティティキャップにより、テナント間でリソースを分配する
- 強制可能な SLA: 定義された上限は、API 応答時間に対する意味のある SLO 設定の前提条件
ネガティブ
- 顧客摩擦: 正当な大量利用ワークロードがデフォルト上限に達し、手動でのクォータ増加が必要になる可能性
- 運用オーバーヘッド: クォータ管理は利用のモニタリングと上限増加リクエストの処理という継続的な作業を追加
- 結果整合性のあるストレージアカウンティング: 利用カウンターは非同期に更新される。大規模アップロード後の短時間、古い使用量が表示される可能性
- 上限チューニングが必要: デフォルト値は初期見積もりであり、観測される本番トラフィックパターンに基づいて調整が必要
検討した代替案
代替案 1: 明示的な上限なし(公正な利用を信頼)
プロアクティブな上限ではなく、モニタリングとリアクティブな介入に依存。
ポジティブ
- 上限に達することからの顧客摩擦なし
- 上限チューニングのオーバーヘッドなし
ネガティブ
- 単一の不適切なテナントがすべての顧客のサービスを劣化させる可能性
- リアクティブな介入は自動強制より遅い
- インシデント中の顧客コミュニケーションの明確な根拠がない
却下理由: GitLab.com 規模では、信頼性のあるマルチテナンシーのためにプロアクティブな上限が必要です。コンテナレジストリの Organization ごとの上限の欠如は 運用上の複雑さ に寄与しました。
代替案 2: インスタンスレベルの上限のみ
namespace ごとではなく、インスタンスレベルでグローバルに上限を適用。
ポジティブ
- 実装と推論がシンプル
ネガティブ
- 単一の大規模 namespace がインスタンス全体のキャパシティを消費するのを防げない
- ビリングとキャパシティプランニングのために、リソース使用量を特定の namespace に按分できない
却下理由: namespace ごとの上限は GitLab.com での公平なマルチテナンシーに必要です。Organization は引き続きアンカーおよび請求ポイントであり(ADR-001)、その namespace の利用量を集約します。
代替案 3: CDN/ロードバランサーのみで上限
すべてのレート上限をアプリケーションではなく CDN またはロードバランサー層(Cloudflare)で強制。
ポジティブ
- レート上限の計算をアプリケーションからオフロード
- スロットルされたリクエストの拒否レイテンシが低い
ネガティブ
- CDN 層の上限は GitLab.com にのみ適用される。Self-Managed インストールには同等の保護がない
- 複雑な CDN 構成なしに namespace ごとの上限を強制できない
却下理由: アプリケーション層のレート制限は、すべての GitLab インストールタイプにわたって一貫した強制を提供します。CDN 層の上限は、IP ベースのスロットリングのためにアプリケーション上限を補完できますが、置き換えることはできません。
実装ノート
Artifact Registry はスタンドアローンサービスです。未解決の質問: 上限とクォータの構成がどこに保存・管理されるか(例: Rails モノリス内に保存しレジストリが API 経由で取得するか、レジストリ内で直接管理するか)はまだ決定されていません。
- ストレージクォータ: アップロードと GC サイクル後に更新される Redis カウンターを使用した、アップロードセッション開始時の非同期チェック
- アーティファクトサイズ: リクエストボディから読み取られるバイトをカウントすることでアップロード中に強制(クライアントが省略または誤報告できる
Content-Lengthヘッダーを信頼しない)。バイト数が上限を超えると読み取りは中断され、リクエストは拒否される。これは Workhorse がアップロードサイズ強制に使用するのと同じアプローチ - レート上限: GCRA アルゴリズムを使用した Redis カウンター。違反時に
Retry-After付き HTTP 429。レート上限実装は、コンテナレジストリ で確立された GCRA ベースのミドルウェアと Redis カウンターパターンを再利用し、構成スキーマを Artifact Registry 固有の操作に適合させる - エンティティ数(アップストリームソース、ライフサイクルポリシールール): 挿入前のデータベースクエリ。違反時に HTTP 422
GitLab.com では、Runway を介したインフラレベルのレート上限が、IP ベースのスロットリングに追加の防御層を提供します。これらはアプリケーションレベルの上限を補完しますが、置き換えるものではありません。アプリケーションレベルの上限は、すべてのインストールタイプにわたる namespace ごとおよびユーザーごとの強制に必要です。
すべての上限違反には、機械可読のエラーコード(例: artifact_registry/quota_exceeded)と、超過した上限を識別する人間可読のメッセージが含まれます。
ロールアウト戦略: レート上限と namespace ごとのクォータは 3 フェーズで導入されます。
- Observe — すべての上限(IP ベース、namespace ごと、ユーザーごと)が構成されますが、メトリクスを発行し警告をログに記録するのみ(ブロックなし)。IP ベースの上限はコンテナレジストリの既存の GCRA ミドルウェアを再利用。このフェーズは、すべての次元にわたるトラフィック分布を収集するために、少なくとも 1 マイルストーン実行されます。
- Warn — namespace ごとまたはユーザーごとの上限を超えるリクエストは警告ヘッダー(例:
X-RateLimit-Remaining)を返しますが、まだサービスされます。上限に近づいている namespace に通知が行われます。 - Enforce — namespace ごとおよびユーザーごとの上限は HTTP 429 応答で能動的に強制されます。デフォルト値はフェーズ 1 と 2 で収集されたデータに基づいて調整されます。
参考文献
- Rate Limiting Architecture Blueprint - 上限、クォータ、ポリシーの区別を定義
- ADR-001: Organizations as Anchor Point - 主要リソース境界としての Organization
- ADR-002: Storage Deduplication Scope - 重複排除済みストレージの計測方法
- ADR-003: System Requirements - スケール目標と強制に使用されるインフラコンポーネント
- Package Registry Rate Limits - ベースラインとして使用される既存のレート上限デフォルト
- Container Registry Rate Limiting Spec - GCRA ベースのレート制限アプローチ
- Container Registry Rate Limiting Implementation - GCRA ベースのレート制限ミドルウェアと構成、Artifact Registry に再利用可能
- GitLab Plan Limits API - 既存のタイプごとアーティファクトサイズ上限
- Managing Limits - レート上限の導入と変更のプロセス
c955a93f)