- Published on
API Gatewayパターン完全ガイド:Rate Limiting、認証/認可、BFFアーキテクチャ設計
- Authors
- Name
- はじめに
- API Gatewayパターン概要
- Rate Limitingアルゴリズム
- 認証/認可戦略
- BFF(Backend for Frontend)アーキテクチャ
- ロードバランシングとサーキットブレーカー
- Kongベースプロダクション実装
- APISIXベースプロダクション実装
- モニタリングと運用
- 障害事例と対応
- 運用チェックリスト
- 参考資料

はじめに
マイクロサービスアーキテクチャが普及するにつれ、クライアントが数十、数百のサービスと直接通信することは現実的に不可能になった。API Gatewayはクライアントとバックエンドサービスの間に位置する単一のエントリーポイントとして、ルーティング、認証/認可、Rate Limiting、ロードバランシング、プロトコル変換などの横断的関心事(cross-cutting concerns)を一元的に処理する。
本記事では、API Gatewayパターンの核心概念から始めて、Rate Limitingアルゴリズム(Token Bucket、Sliding Window、Fixed Window、Leaky Bucket)の動作原理と比較、JWT/OAuth2ベースの認証/認可戦略、BFF(Backend for Frontend)アーキテクチャ設計、ロードバランシングとサーキットブレーカー構成、そしてKongとApache APISIXベースのプロダクション実装例を扱う。最後に、プロダクション環境で実際に遭遇しうる障害シナリオと運用チェックリストを整理する。
API Gatewayパターン概要
API Gatewayの役割
API Gatewayは以下の横断的関心事を一元的に処理する。
- ルーティング:リクエストURL、ヘッダー、メソッドに基づいて適切なバックエンドサービスに転送
- 認証/認可:JWT検証、OAuth2トークン有効性検査、APIキー管理
- Rate Limiting:クライアント別、API別リクエスト速度制限
- ロードバランシング:ラウンドロビン、加重、最小接続などのアルゴリズムでトラフィック分散
- サーキットブレーカー:障害サービスへのリクエストを自動遮断して連鎖障害防止
- プロトコル変換:REST to gRPC、HTTP to WebSocketなど
- キャッシング:レスポンスキャッシングによるパフォーマンス向上
- モニタリング:メトリクス収集、分散トレーシング、ロギング
API Gatewayソリューション比較
| 項目 | Kong | Apache APISIX | AWS API Gateway | Envoy |
|---|---|---|---|---|
| 基盤技術 | NGINX + Lua | NGINX + etcd | AWSマネージド | C++ |
| 性能 (QPS) | 約10,000+ | 約23,000+ | マネージド(制限あり) | 約15,000+ |
| プラグイン | 非常に豊富 (100+) | 豊富 (80+) | 限定的 | 豊富(フィルターチェーン) |
| 設定ストア | PostgreSQL / Cassandra | etcd | AWS内部 | xDS API |
| 動的設定変更 | Admin API | Admin API + etcd Watch | コンソール/CLI | xDSホットリロード |
| サービスメッシュ | Kong Mesh (Kuma) | Amesh (Istio連携) | App Mesh連携 | Istioデフォルトプロキシ |
| Kubernetesネイティブ | Kong Ingress Controller | APISIX Ingress Controller | なし(EKS連携) | Gateway APIサポート |
| ライセンス | Apache 2.0 / Enterprise | Apache 2.0 | 従量課金 | Apache 2.0 |
| 適合環境 | 汎用、エンタープライズ | 高性能、動的ルーティング | AWSネイティブ | K8s、サービスメッシュ |
API Gateway vs サービスメッシュ
API Gatewayとサービスメッシュは補完的な関係である。
| 区分 | API Gateway | サービスメッシュ |
|---|---|---|
| 位置 | クライアントとサービスの間(南北トラフィック) | サービスとサービスの間(東西トラフィック) |
| 主な役割 | 外部リクエストルーティング、認証、Rate Limiting | サービス間mTLS、トラフィック管理、オブザーバビリティ |
| デプロイ方式 | 集中型(ゲートウェイクラスター) | 分散型(サイドカープロキシ) |
| プロトコル | HTTP、gRPC、WebSocket | TCP、HTTP、gRPC |
| 代表ソリューション | Kong、APISIX、AWS API GW | Istio、Linkerd、Consul Connect |
Rate Limitingアルゴリズム
Rate LimitingはAPI Gatewayの最も重要な機能の一つである。サービスの過負荷防止、DDoS防御、公平なリソース分配のために不可欠である。
アルゴリズム比較
| アルゴリズム | 原理 | バースト許容 | メモリ使用量 | 精度 | 実装複雑度 |
|---|---|---|---|---|---|
| Fixed Window | 固定時間ウィンドウ内カウンター | 境界で2倍可能 | 低い | 低い | 非常に低い |
| Sliding Window Log | 各リクエストのタイムスタンプ記録 | なし | 高い | 高い | 中間 |
| Sliding Window Counter | 前/現在ウィンドウの加重平均 | 最小化 | 低い | 中間 | 中間 |
| Token Bucket | 一定速度でトークン補充、リクエスト時消費 | 許容(バケットサイズまで) | 低い | 中間 | 低い |
| Leaky Bucket | 固定速度でリクエスト処理、超過分キューイング | なし(固定速度) | 低い | 高い | 低い |
Token Bucketアルゴリズム
Token Bucketはバーストトラフィックを許容しながら平均リクエストレートを制限する最も実用的なアルゴリズムである。
# Kong - Rate Limitingプラグイン設定(Token Bucketベース)
# kong.yml - Declarative Configuration
_format_version: '3.0'
services:
- name: user-service
url: http://user-service:8080
routes:
- name: user-route
paths:
- /api/v1/users
plugins:
- name: rate-limiting
config:
# 毎分100回、毎時1000回制限
minute: 100
hour: 1000
# ポリシー: local(単一ノード)、cluster(クラスター全体)、redis(Redisベース)
policy: redis
redis:
host: redis-cluster
port: 6379
password: null
database: 0
timeout: 2000
# Rate Limitヘッダー返却
header_name: null
hide_client_headers: false
# 制限基準: consumer, credential, ip, header, path, service
limit_by: consumer
# Redis障害時リクエスト許可
fault_tolerant: true
Sliding Windowアルゴリズム
Sliding Window CounterはFixed Windowの境界問題を解決しながらメモリ効率が良い。
-- APISIX カスタムRate Limitingプラグイン(Sliding Window Counter)
-- apisix/plugins/sliding-window-rate-limit.lua
local core = require("apisix.core")
local ngx = ngx
local math = math
local schema = {
type = "object",
properties = {
rate = { type = "integer", minimum = 1 },
burst = { type = "integer", minimum = 0 },
window_size = { type = "integer", minimum = 1, default = 60 },
key_type = {
type = "string",
enum = { "remote_addr", "consumer_name", "header" },
default = "remote_addr"
},
},
required = { "rate" },
}
local _M = {
version = 0.1,
priority = 1001,
name = "sliding-window-rate-limit",
schema = schema,
}
function _M.access(conf, ctx)
local key = ctx.var.remote_addr
if conf.key_type == "consumer_name" then
key = ctx.consumer_name or ctx.var.remote_addr
end
local now = ngx.now()
local window = conf.window_size
local current_window = math.floor(now / window) * window
local previous_window = current_window - window
local elapsed = now - current_window
-- 前ウィンドウと現在ウィンドウの加重平均計算
local prev_count = get_count(key, previous_window) or 0
local curr_count = get_count(key, current_window) or 0
local weight = (window - elapsed) / window
local estimated = prev_count * weight + curr_count
if estimated >= conf.rate then
return 429, {
error = "Rate limit exceeded",
retry_after = math.ceil(window - elapsed)
}
end
increment_count(key, current_window)
end
return _M
認証/認可戦略
API Gatewayでの認証/認可はバックエンドサービスのセキュリティ負担を大幅に軽減する。
JWT認証設定
# APISIX - JWT認証プラグイン設定
# apisix/conf/config.yaml
routes:
- uri: /api/v1/orders/*
upstream:
type: roundrobin
nodes:
'order-service:8080': 1
plugins:
jwt-auth:
# JWT署名検証用の公開鍵
key: 'user-auth-key'
# トークン位置設定
header: 'Authorization'
query: 'token'
cookie: 'jwt_token'
# 追加:権限ベースアクセス制御
consumer-restriction:
type: consumer_group_id
whitelist:
- 'premium-users'
- 'admin-group'
rejected_code: 403
rejected_msg: 'Access denied: insufficient permissions'
# Consumer設定(APIユーザー定義)
consumers:
- username: 'mobile-app'
plugins:
jwt-auth:
key: 'mobile-app-key'
secret: 'mobile-app-secret-256bit-key-here'
algorithm: 'HS256'
exp: 86400 # トークン有効期限:24時間
base64_secret: false
- username: 'web-frontend'
plugins:
jwt-auth:
key: 'web-frontend-key'
# RS256使用時の公開鍵パス
public_key: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----
algorithm: 'RS256'
exp: 3600 # トークン有効期限:1時間
OAuth2 + OIDC統合認証フロー
API GatewayでOAuth2/OIDCを統合すると、IdP(Identity Provider)との連携を一元化できる。
# Kong - OpenID Connectプラグイン設定
plugins:
- name: openid-connect
config:
issuer: 'https://auth.example.com/realms/production'
client_id: 'api-gateway'
client_secret: 'gateway-secret-value'
redirect_uri: 'https://api.example.com/callback'
# サポート認証フロー
auth_methods:
- authorization_code # Webアプリケーション
- client_credentials # サービス間通信
- password # レガシーサポート(非推奨)
# トークン検証設定
token_endpoint_auth_method: client_secret_post
# スコープベースアクセス制御
scopes_required:
- openid
- profile
- api:read
# トークンキャッシング(パフォーマンス最適化)
cache_ttl: 300
# トークンイントロスペクション(不透明トークン検証)
introspection_endpoint: 'https://auth.example.com/realms/production/protocol/openid-connect/token/introspect'
# アップストリームに転送するヘッダー
upstream_headers_claims:
- sub
- email
- realm_access.roles
upstream_headers_names:
- X-User-ID
- X-User-Email
- X-User-Roles
BFF(Backend for Frontend)アーキテクチャ
BFFパターンが必要な理由
単一のAPI Gatewayで全クライアント(Web、モバイル、IoTなど)にサービスを提供すると、以下の問題が発生する。
- 過剰なデータ転送:モバイルクライアントにWeb用の全データが送信される
- 複雑なゲートウェイロジック:クライアント別の分岐ロジックがゲートウェイに蓄積される
- デプロイ結合:一つのクライアントのための変更が他のクライアントに影響
BFFパターンは各フロントエンドに最適化された専用バックエンドを提供してこれらの問題を解決する。
BFFルーティング構成
# APISIX - BFFルーティング設定
# クライアントタイプ別の専用BFFにルーティング
routes:
# Web BFF - 豊富なデータ、詳細情報含む
- uri: /api/web/*
name: web-bff-route
plugins:
proxy-rewrite:
regex_uri:
- '^/api/web/(.*)'
- '/$1'
request-id:
header_name: X-Request-ID
jwt-auth: {}
rate-limiting:
rate: 200
burst: 50
key_type: consumer_name
upstream:
type: roundrobin
nodes:
'web-bff:3000': 1
timeout:
connect: 3
send: 10
read: 30
# モバイルBFF - 軽量データ、ページネーション最適化
- uri: /api/mobile/*
name: mobile-bff-route
plugins:
proxy-rewrite:
regex_uri:
- '^/api/mobile/(.*)'
- '/$1'
jwt-auth: {}
rate-limiting:
rate: 100
burst: 20
key_type: consumer_name
# モバイル専用:レスポンスサイズ制御
response-rewrite:
headers:
set:
X-Content-Optimized: 'mobile'
upstream:
type: roundrobin
nodes:
'mobile-bff:3001': 1
timeout:
connect: 3
send: 5
read: 15
# IoT BFF - 最小データ、高頻度
- uri: /api/iot/*
name: iot-bff-route
plugins:
proxy-rewrite:
regex_uri:
- '^/api/iot/(.*)'
- '/$1'
key-auth: {} # IoTデバイスはAPIキー認証
rate-limiting:
rate: 500
burst: 100
key_type: var
key: remote_addr
upstream:
type: roundrobin
nodes:
'iot-bff:3002': 1
timeout:
connect: 2
send: 3
read: 5
BFFアーキテクチャ構造
クライアント層 API Gateway BFF層 マイクロサービス
+----------+ +----------+
| Web App | ----+ +--> | Web BFF | --+--> User Service
+----------+ | +-----------+ | +----------+ +--> Product Service
+--> | |--+ +--> Order Service
+----------+ | | API | | +----------+
|Mobile App| ----+--> | Gateway |--+--> |Mobile BFF| --+--> User Service
+----------+ | | | | +----------+ +--> Product Service
| +-----------+ |
+----------+ | | +----------+
|IoT Device| ----+ +--> | IoT BFF | --+--> Device Service
+----------+ +----------+ +--> Telemetry Service
ロードバランシングとサーキットブレーカー
ロードバランシング戦略
API Gatewayは多様なロードバランシングアルゴリズムをサポートする。
# APISIX - ロードバランシング戦略
upstreams:
# 加重ラウンドロビン
- id: 1
type: roundrobin
nodes:
'service-a-v1:8080': 8 # 80%トラフィック
'service-a-v2:8080': 2 # 20%トラフィック(カナリアデプロイ)
# ヘルスチェック設定
checks:
active:
type: http
http_path: /health
healthy:
interval: 5
successes: 2
unhealthy:
interval: 3
http_failures: 3
tcp_failures: 3
passive:
healthy:
http_statuses:
- 200
- 201
successes: 3
unhealthy:
http_statuses:
- 500
- 502
- 503
http_failures: 5
tcp_failures: 2
# コンシステントハッシュ(セッションアフィニティ)
- id: 2
type: chash
key: remote_addr
nodes:
'session-service-1:8080': 1
'session-service-2:8080': 1
'session-service-3:8080': 1
# 最小接続
- id: 3
type: least_conn
nodes:
'compute-service-1:8080': 1
'compute-service-2:8080': 1
サーキットブレーカー設定
# APISIX - api-breakerプラグイン(自動サーキットブレーカー)
routes:
- uri: /api/v1/payments/*
plugins:
api-breaker:
# サーキットブレーカートリガーステータスコード
break_response_code: 503
break_response_body: '{"error":"circuit open","retry_after":30}'
break_response_headers:
- key: Content-Type
value: application/json
- key: Retry-After
value: '30'
# unhealthy判定:連続3回500エラーでサーキットオープン
unhealthy:
http_statuses:
- 500
- 502
- 503
failures: 3
# healthy判定:連続2回成功でサーキットクローズ
healthy:
http_statuses:
- 200
- 201
successes: 2
# サーキットオープン後の最大待機時間(秒)
max_breaker_sec: 300
upstream:
type: roundrobin
nodes:
'payment-service:8080': 1
Kongベースプロダクション実装
Docker ComposeベースKongクラスター構成
# docker-compose.kong.yml
version: '3.8'
services:
kong-database:
image: postgres:15-alpine
environment:
POSTGRES_DB: kong
POSTGRES_USER: kong
POSTGRES_PASSWORD: kong_password
volumes:
- kong_pgdata:/var/lib/postgresql/data
healthcheck:
test: ['CMD', 'pg_isready', '-U', 'kong']
interval: 10s
timeout: 5s
retries: 5
kong-migration:
image: kong:3.6
command: kong migrations bootstrap
depends_on:
kong-database:
condition: service_healthy
environment:
KONG_DATABASE: postgres
KONG_PG_HOST: kong-database
KONG_PG_USER: kong
KONG_PG_PASSWORD: kong_password
kong:
image: kong:3.6
depends_on:
kong-migration:
condition: service_completed_successfully
environment:
KONG_DATABASE: postgres
KONG_PG_HOST: kong-database
KONG_PG_USER: kong
KONG_PG_PASSWORD: kong_password
KONG_PROXY_ACCESS_LOG: /dev/stdout
KONG_ADMIN_ACCESS_LOG: /dev/stdout
KONG_PROXY_ERROR_LOG: /dev/stderr
KONG_ADMIN_ERROR_LOG: /dev/stderr
KONG_ADMIN_LISTEN: '0.0.0.0:8001'
KONG_STATUS_LISTEN: '0.0.0.0:8100'
# パフォーマンスチューニング
KONG_NGINX_WORKER_PROCESSES: auto
KONG_UPSTREAM_KEEPALIVE_POOL_SIZE: 128
KONG_UPSTREAM_KEEPALIVE_MAX_REQUESTS: 1000
ports:
- '8000:8000' # プロキシ(HTTP)
- '8443:8443' # プロキシ(HTTPS)
- '8001:8001' # Admin API
healthcheck:
test: ['CMD', 'kong', 'health']
interval: 10s
timeout: 5s
retries: 5
volumes:
kong_pgdata:
APISIXベースプロダクション実装
APISIX HelmベースKubernetesデプロイ
# APISIX Kubernetesデプロイ(Helm)
helm repo add apisix https://charts.apiseven.com
helm repo update
# APISIXインストール(etcd含む)
helm install apisix apisix/apisix \
--namespace apisix \
--create-namespace \
--set gateway.type=LoadBalancer \
--set ingress-controller.enabled=true \
--set dashboard.enabled=true \
--set etcd.replicaCount=3 \
--set etcd.persistence.size=20Gi \
--set apisix.nginx.workerProcesses=auto \
--set apisix.nginx.workerConnections=65536
# APISIX状態確認
kubectl -n apisix get pods
kubectl -n apisix get svc
# Admin APIによるルート登録
curl -X PUT http://apisix-admin:9180/apisix/admin/routes/1 \
-H "X-API-KEY: admin-api-key" \
-d '{
"uri": "/api/v1/products/*",
"upstream": {
"type": "roundrobin",
"nodes": {
"product-service.default.svc:8080": 1
}
},
"plugins": {
"jwt-auth": {},
"limit-count": {
"count": 200,
"time_window": 60,
"rejected_code": 429,
"rejected_msg": "Rate limit exceeded. Please retry later.",
"policy": "redis",
"redis_host": "redis.default.svc",
"redis_port": 6379,
"key_type": "var",
"key": "consumer_name"
},
"api-breaker": {
"break_response_code": 503,
"unhealthy": {
"http_statuses": [500, 502, 503],
"failures": 3
},
"healthy": {
"http_statuses": [200],
"successes": 2
},
"max_breaker_sec": 60
}
}
}'
モニタリングと運用
Prometheus + Grafanaメトリクス収集
API Gatewayの核心モニタリングメトリクスは以下の通りである。
- リクエストレート(Request Rate):毎秒処理リクエスト数
- エラーレート(Error Rate):4xx/5xxレスポンス比率
- レイテンシ(Latency):P50、P95、P99レスポンス時間
- Rate Limitヒット率:制限に到達したリクエスト比率
- サーキットブレーカー状態:Open/Closed/Half-Open遷移イベント
- アップストリームヘルス:バックエンドサービス可用性
# APISIX - Prometheusメトリクス収集設定
plugin_attr:
prometheus:
export_uri: /apisix/prometheus/metrics
export_addr:
ip: '0.0.0.0'
port: 9091
default_buckets:
- 0.005
- 0.01
- 0.025
- 0.05
- 0.1
- 0.25
- 0.5
- 1
- 2.5
- 5
- 10
# グローバルプラグインで全ルートに適用
global_rules:
- id: 1
plugins:
prometheus:
prefer_name: true
# 分散トレーシング(OpenTelemetry)
opentelemetry:
sampler:
name: parent_based_traceidratio
options:
fraction: 0.1 # 10%サンプリング
additional_attributes:
- 'service.version'
核心アラートルール
# Prometheus Alert Rules
groups:
- name: api-gateway-alerts
rules:
- alert: HighErrorRate
expr: |
sum(rate(apisix_http_status{code=~"5.."}[5m]))
/ sum(rate(apisix_http_status[5m])) > 0.05
for: 2m
labels:
severity: critical
annotations:
summary: 'API Gateway 5xxエラー率5%超過'
- alert: HighLatency
expr: |
histogram_quantile(0.99,
sum(rate(apisix_http_latency_bucket[5m])) by (le, route)
) > 2000
for: 5m
labels:
severity: warning
annotations:
summary: 'API Gateway P99レイテンシ2秒超過'
- alert: RateLimitExceeded
expr: |
sum(rate(apisix_http_status{code="429"}[5m])) > 100
for: 1m
labels:
severity: warning
annotations:
summary: 'Rate Limit超過リクエスト毎分100件以上'
障害事例と対応
事例1:Rate Limiter設定ミスによるサービス障害
あるフィンテック企業でRate Limiterをlocalポリシーで設定したままAPI Gatewayを3台にスケールアウトした。各ノードが独立的にRate Limitを適用したため、実際には設定値の3倍のトラフィックがバックエンドに転送され、決済サービスが過負荷でダウンした。
対応:分散環境では必ずredisまたはclusterポリシーを使用する必要がある。Redis ClusterをRate Limitストアとして使用すれば、ノード数に関係なく一貫した制限を適用できる。
事例2:API Gateway単一障害点(Single Point of Failure)
API Gatewayが単一インスタンスで運用されていた中、メモリリークによりOOM(Out of Memory)が発生し、サービス全体が停止した。
対応:API Gatewayは必ずHA(High Availability)構成で運用する必要がある。最低2台以上のインスタンスをActive-Activeでデプロイし、L4ロードバランサー(AWS NLB、MetalLB)を前段に配置する。ヘルスチェックで障害ノードを自動的に除去する。
事例3:認証トークンキャッシングによる権限エスカレーション
JWTトークンをAPI Gatewayで5分間キャッシングするように設定したが、ユーザーの権限が変更されたりアカウントが無効化された後もキャッシュされたトークンでアクセスが可能だった。
対応:トークンキャッシュTTLを短く維持し(30秒~1分)、重要な権限変更時にトークンブラックリストを使用する。Gatewayでexpクレームを必ず検証し、トークンリボケーションエンドポイントを実装する。
事例4:サーキットブレーカー未設定による連鎖障害
外部決済APIのレスポンス遅延が60秒以上に増加したが、サーキットブレーカーが設定されていなかったため、API Gatewayの全ワーカープロセスが決済サービス待機で占有された。その結果、正常な他のAPIもレスポンスできなくなった。
対応:全アップストリームに適切なタイムアウトとサーキットブレーカーを設定する。接続タイムアウトは3秒、読み取りタイムアウトはAPI特性に応じて530秒に制限する。連続35回失敗時にサーキットをオープンし、30~60秒後にHalf-Open状態に遷移して段階的に復旧する。
運用チェックリスト
プロダクション環境でAPI Gatewayを運用する際に確認すべき核心項目である。
デプロイと可用性
- HA構成(最低2台以上、Active-Active)
- L4ロードバランサー前段配置(AWS NLB、MetalLBなど)
- ローリングアップデートまたはブルーグリーンデプロイ戦略
- 設定ストアバックアップ(PostgreSQL、etcd)
セキュリティ
- Admin APIアクセス制限(内部ネットワークのみ許可)
- TLS 1.3適用および証明書自動更新
- JWTトークン検証有効化およびキャッシュTTL最小化
- CORS、CSRF保護設定
Rate Limiting
- 分散ポリシー使用(redisまたはcluster)
- クライアントタイプ別差等制限設定
- Rate Limitヘッダー返却(X-RateLimit-Limit、X-RateLimit-Remaining)
- Redis障害時fault_tolerant設定
モニタリング
- Prometheusメトリクス収集有効化
- P99レイテンシ、エラーレート、Rate Limitヒット率ダッシュボード
- サーキットブレーカー状態変更アラート
- 分散トレーシング(OpenTelemetry)連携
パフォーマンス
- ワーカープロセス数最適化(CPUコア数基準)
- アップストリームKeepalive接続プール設定
- レスポンスキャッシング戦略適用
- 不要なプラグイン無効化