Documentation
¶
Overview ¶
Package ratelimit 提供基于键的限流原语:令牌桶 + 滑动窗口两种实现, 外加 HTTP 中间件,可与 pkg/handler 组合(声明式 WithRatelimit)。
设计要点(per-user 限流 + 通用 token bucket):
- Limiter 接口:Allow(key) (allowed, retryAfter),按 key 隔离(如按 userID / IP);
- TokenBucket:固定速率补令牌,允许突发;无锁化设计用 sync.Map + 互斥桶;
- SlidingWindow:滑动窗口(精确),用时间戳 deque;
- HTTP middleware:超限返回 429 + Retry-After 头;
- 后台 gc:清理长时间无活动的 key,避免内存泄漏(参考 pkg/token 的 gc 模式)。
零值不可用,用 New 构造。Limiter 并发安全;Stop 后 gc goroutine 退出。
Index ¶
- func ClientIP(r *http.Request) string
- func Middleware(l Limiter, keyFn KeyFunc) func(http.Handler) http.Handler
- func MiddlewareWithLimiter(l Limiter, keyFn KeyFunc) func(http.Handler) http.Handler
- func WithLimiter(ctx context.Context, l Limiter) context.Context
- type GCRA
- type KeyFunc
- type Limiter
- type Option
- type RetryBudget
- type SlidingWindow
- type TokenBucket
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Middleware ¶
Middleware 返回 HTTP 限流中间件:keyFn 提取 key,limiter 限流。 超限返回 429 + Retry-After 头(秒级)。keyFn 返回空串则跳过限流。
func MiddlewareWithLimiter ¶
MiddlewareWithLimiter 返回带 limiter 注入 ctx 的中间件:下游 handler 可用 FromContext 取 limiter 做更细粒度限流(如对某资源再限一次)。
Types ¶
type GCRA ¶ added in v0.3.0
type GCRA struct {
// contains filtered or unexported fields
}
GCRA(Generic Cell Rate Algorithm)限流器:漏桶的一种精巧实现——每个 key 只维护一个 "理论到达时间"(TAT),放行判断只是一次时间算术,无后台补令牌、无请求时间戳队列, 输出天然平滑且支持突发。相较令牌桶/滑动窗口,内存最省(每 key 一个时间戳)、无锯齿。
参数:rate 为每秒允许的稳定速率(emission = 1s/rate 为两次放行的最小间隔); burst 为可一次性突发的数量(容忍度 τ = emission*burst)。rate<=0 或 burst<=0 视为不限。
实现 Limiter,可直接接 Middleware。并发安全;Stop 后 gc 退出。
type Limiter ¶
Limiter 限流器接口。按 key 隔离(每个 key 独立计数)。 返回 (allowed, retryAfter):retryAfter=0 表示立即可重试或已放行。
func FromContext ¶
FromContext 从 ctx 取出 Limiter(没有则 nil)。
type Option ¶
type Option func(*config)
Option 配置限流器。
func WithGcInterval ¶
WithGcInterval 设置 gc 扫描间隔。默认 1min。
func WithMaxIdle ¶
WithMaxIdle 设置 key 最大空闲时长(超过则被 gc 回收)。默认 5min。
type RetryBudget ¶ added in v0.3.0
type RetryBudget struct {
// contains filtered or unexported fields
}
RetryBudget 是"重试预算"(gRPC retry throttling 模型):用一个令牌余额约束重试**占比**, 防止在下游普遍失败时,重试把下游进一步压垮(重试风暴)。它不限制单次重试的时机,而是限制 "重试/请求"的整体比率——下游健康时余额充足、放行重试;下游持续失败会迅速耗尽余额、抑制重试。
模型:余额上限 maxTokens,初始为满;每完成一个请求(成功或不可重试的失败)Deposit 加 tokenRatio; 每次重试尝试 Allow 花 1 个令牌,且仅当余额 > maxTokens/2 时才放行。并发安全。
用法:
resp, err := call()
for retryable(err) && budget.Allow() {
resp, err = call()
}
budget.Deposit() // 本次请求最终完成(无论成败),归还额度
func NewRetryBudget ¶ added in v0.3.0
func NewRetryBudget(maxTokens int, tokenRatio float64) *RetryBudget
NewRetryBudget 创建重试预算。maxTokens 为余额上限(如 100),tokenRatio 为每个完成请求归还的令牌数 (如 0.1,表示大约每 10 个正常请求才攒够 1 次重试的额度)。参数非法时用保守默认(max=100,ratio=0.1)。
func (*RetryBudget) Allow ¶ added in v0.3.0
func (b *RetryBudget) Allow() bool
Allow 尝试为"一次重试"花 1 个令牌:仅当余额 > 阈值(maxTokens/2)时放行并扣减,返回是否允许重试。
func (*RetryBudget) Deposit ¶ added in v0.3.0
func (b *RetryBudget) Deposit()
Deposit 在一个请求最终完成(成功或不可重试失败)时调用,归还 tokenRatio 个令牌(封顶 maxTokens)。
func (*RetryBudget) Tokens ¶ added in v0.3.0
func (b *RetryBudget) Tokens() float64
Tokens 返回当前余额(用于观测/调试)。
type SlidingWindow ¶
type SlidingWindow struct {
// contains filtered or unexported fields
}
SlidingWindow 滑动窗口限流器:在 window 时长内最多 limit 次请求,精确计数。
func NewSlidingWindow ¶
func NewSlidingWindow(limit int, window time.Duration, opts ...Option) *SlidingWindow
NewSlidingWindow 创建滑动窗口限流器。limit<=0 或 window<=0 视为不限。
func (*SlidingWindow) Allow ¶
func (sw *SlidingWindow) Allow(key string) (bool, time.Duration)
Allow 按 key 限流。滑动窗口:清除早于 window 的旧记录后判断数量。
func (*SlidingWindow) String ¶
func (sw *SlidingWindow) String() string
type TokenBucket ¶
type TokenBucket struct {
// contains filtered or unexported fields
}
TokenBucket 令牌桶限流器:固定速率补令牌,允许突发(初始满桶)。 burst 为桶容量(最大突发数),rate 为每秒补充令牌数。
func NewTokenBucket ¶
func NewTokenBucket(burst int, rate float64, opts ...Option) *TokenBucket
NewTokenBucket 创建令牌桶限流器。burst<=0 或 rate<=0 视为不限(Allow 永远 true)。 gc 每 gcInterval 清理一次超过 maxIdle 无活动的 key。