mcpField
R
rate-limiting

rate-limiting

github.com/claude-dev-suite開発4640 回インストール2 日前に更新
リポジトリ

rate-limiting について

開発者向けのレート制限の実装ガイドです。Express と Spring Boot の例、Redis のスライディングウィンドウ、アルゴリズム比較を通じて方式やレスポンスヘッダーの設定を扱います。

主な機能

  1. 01Express のレート制限例
  2. 02Redis スライディングウィンドウ実装
  3. 03レート制限アルゴリズムの比較
  4. 04Spring Boot と Bucket4j の例
  5. 05レスポンスヘッダーと本番チェックリスト

活用シーン

  1. 01API のリクエスト数を制限
  2. 02複数サーバーで Redis 制限を利用
  3. 03レート制限アルゴリズムを比較
  4. 04429 レスポンスと再試行案内を設定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill rate-limiting

インストール後、Claude Code で/rate-limitingを入力して読み込まれたか確認します。

詳細

レート制限

Express (express-rate-limit)

import rateLimit from 'express-rate-limit';
import RedisStore from 'rate-limit-redis';
import { createClient } from 'redis';

const redis = createClient({ url: process.env.REDIS_URL });

// Global rate limit
const globalLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  limit: 100,
  standardHeaders: 'draft-7',
  legacyHeaders: false,
  store: new RedisStore({ sendCommand: (...args) => redis.sendCommand(args) }),
  message: { error: 'Too many requests, try again later' },
});

app.use(globalLimiter);

// Stricter limit on auth endpoints
const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  limit: 5,
  keyGenerator: (req) => req.body.email || req.ip, // By email, not just IP
  store: new RedisStore({ sendCommand: (...args) => redis.sendCommand(args) }),
});

app.use('/api/auth/login', authLimiter);

Redis スライディングウィンドウ(カスタム)

async function isRateLimited(key: string, limit: number, windowSec: number): Promise<boolean> {
  const now = Date.now();
  const windowStart = now - windowSec * 1000;

  const multi = redis.multi();
  multi.zRemRangeByScore(key, 0, windowStart);    // Remove old entries
  multi.zAdd(key, { score: now, value: `${now}` });
  multi.zCard(key);                                  // Count in window
  multi.expire(key, windowSec);

  const results = await multi.exec();
  const count = results![2] as number;
  return count > limit;
}

// Usage
if (await isRateLimited(`rl:${userId}`, 100, 60)) {
  return res.status(429).json({ error: 'Rate limit exceeded' });
}

アルゴリズムの比較

アルゴリズム精度メモリ使用量最適な用途
固定ウィンドウ低(境界でバーストが発生)非常に少ないシンプルな API
スライディングウィンドウログ高中程度正確な制限
スライディングウィンドウカウンター中少ない精度とメモリ使用量のバランス
トークンバケット中少ないバーストに対応する API

Spring Boot (Bucket4j)

@Bean
public FilterRegistrationBean<RateLimitFilter> rateLimitFilter() {
    var filter = new RateLimitFilter(
        Bandwidth.classic(100, Refill.intervally(100, Duration.ofMinutes(1)))
    );
    var registration = new FilterRegistrationBean<>(filter);
    registration.addUrlPatterns("/api/*");
    return registration;
}

レスポンスヘッダー

// Standard rate limit headers (RFC draft-7)
res.set({
  'RateLimit-Limit': '100',
  'RateLimit-Remaining': `${remaining}`,
  'RateLimit-Reset': `${resetTimestamp}`,
  'Retry-After': `${retryAfterSeconds}`, // On 429 responses
});

アンチパターン

アンチパターン修正方法
複数サーバー構成でのメモリ内レート制限Redis ベースのストアを使用する
IP のみでレート制限するユーザー ID または API キーでも制限する
レスポンスにレート制限ヘッダーがないクライアントが状況を把握できるよう RateLimit-* ヘッダーを送信する
すべてのエンドポイントで同じ制限を適用する認証、Webhook、負荷の高い処理にはより厳しい制限を設定する
429 レスポンスに Retry-After がないRetry-After ヘッダーを含める

本番環境チェックリスト

  • 分散デプロイメント向けに Redis ベースのレート制限を使用する
  • エンドポイントごとにレート制限を設定する
  • レスポンスに標準のレート制限ヘッダーを含める
  • 429 レスポンスに Retry-After ヘッダーを含める
  • ユーザー ID(IP だけでなく)でレート制限する
  • 監視:レート制限に達した頻度

コメント