---
title: API网关速率限制与配额策略(租户级/用户级)最佳实践
keywords:
- 速率限制
- 配额
- 滑动窗口
- 令牌桶
- 租户限流
- 用户限流
- 路由维度
- 突发控制
- 持续速率
- 观测与审计
description: 构建租户级与用户级的速率限制与配额策略,结合滑动窗口与令牌桶实现突发与持续速率控制,附可验证的限流引擎与路由整合示例。
categories:
- 文章资讯
- 技术教程
---
一、目标与参数
- 支持租户、用户与路由维度的组合Key;最小窗口与上限参数可验证。
- 突发与持续双策略:滑动窗口用于峰值限制,令牌桶用于持续速率。
二、滑动窗口
class SlidingWindowLimiter {
windowMs: number
limit: number
hits = new Map<string, number[]>()
constructor(windowMs: number, limit: number) { this.windowMs = windowMs; this.limit = limit }
allow(key: string): { ok: boolean; remaining: number } {
const now = Date.now()
const arr = (this.hits.get(key) || []).filter(t => now - t < this.windowMs)
if (arr.length >= this.limit) return { ok: false, remaining: 0 }
arr.push(now)
this.hits.set(key, arr)
return { ok: true, remaining: Math.max(0, this.limit - arr.length) }
}
}
三、令牌桶
class TokenBucketLimiter {
capacity: number
refillPerSec: number
buckets = new Map<string, { tokens: number; ts: number }>()
constructor(capacity: number, refillPerSec: number) { this.capacity = capacity; this.refillPerSec = refillPerSec }
allow(key: string): { ok: boolean; tokens: number } {
const now = Date.now()
const b = this.buckets.get(key) || { tokens: this.capacity, ts: now }
const elapsed = (now - b.ts) / 1000
b.tokens = Math.min(this.capacity, b.tokens + elapsed * this.refillPerSec)
b.ts = now
if (b.tokens < 1) { this.buckets.set(key, b); return { ok: false, tokens: Math.floor(b.tokens) } }
b.tokens -= 1
this.buckets.set(key, b)
return { ok: true, tokens: Math.floor(b.tokens) }
}
}
四、组合策略与路由整合
type Req = { headers: Record<string, string | undefined>; path: string }
type Res = { status: (n: number) => Res; end: (b?: string) => void; setHeader: (k: string, v: string) => void }
class CompositeLimiter {
win: SlidingWindowLimiter
bucket: TokenBucketLimiter
constructor(win: SlidingWindowLimiter, bucket: TokenBucketLimiter) { this.win = win; this.bucket = bucket }
allow(key: string): boolean {
const a = this.win.allow(key)
if (!a.ok) return false
const b = this.bucket.allow(key)
return b.ok
}
}
function keyOf(req: Req): string {
const tenant = req.headers['x-tenant-id'] || 'anon'
const user = req.headers['x-user-id'] || 'anon'
return `${tenant}:${user}:${req.path}`
}
function rateGuard(limiter: CompositeLimiter) {
return function handler(req: Req, res: Res, next: Function) {
const key = keyOf(req)
if (!limiter.allow(key)) {
res.setHeader('Retry-After', '1')
return res.status(429).end('rate_limited')
}
next()
}
}
五、配额管理
class QuotaStore {
counts = new Map<string, number>()
limit: number
constructor(limit: number) { this.limit = limit }
add(key: string, n: number): boolean {
const v = (this.counts.get(key) || 0) + n
if (v > this.limit) return false
this.counts.set(key, v)
return true
}
remaining(key: string): number { return Math.max(0, this.limit - (this.counts.get(key) || 0)) }
}
function quotaGuard(store: QuotaStore) {
return function handler(req: Req, res: Res, next: Function) {
const key = keyOf(req)
const ok = store.add(key, 1)
if (!ok) return res.status(403).end('quota_exceeded')
next()
}
}
六、验收清单
- 最小窗口
windowMs≥1000与滑动上限通过;令牌桶容量与补充速率生效。 - 租户/用户/路由组合Key验证;速率限制返回
429并包含Retry-After。 - 配额计数可靠并可查询剩余;审计记录包含组合Key与路由信息。

发表评论 取消回复