ratelimit

package
v0.7.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 14, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

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

Constants

This section is empty.

Variables

This section is empty.

Functions

func ClientIP

func ClientIP(r *http.Request) string

ClientIP 从请求提取客户端 IP(优先 X-Forwarded-For,其次 RemoteAddr)。

func Middleware

func Middleware(l Limiter, keyFn KeyFunc) func(http.Handler) http.Handler

Middleware 返回 HTTP 限流中间件:keyFn 提取 key,limiter 限流。 超限返回 429 + Retry-After 头(秒级)。keyFn 返回空串则跳过限流。

func MiddlewareWithLimiter

func MiddlewareWithLimiter(l Limiter, keyFn KeyFunc) func(http.Handler) http.Handler

MiddlewareWithLimiter 返回带 limiter 注入 ctx 的中间件:下游 handler 可用 FromContext 取 limiter 做更细粒度限流(如对某资源再限一次)。

func WithLimiter

func WithLimiter(ctx context.Context, l Limiter) context.Context

WithLimiter 把 limiter 装入 ctx。供 pkg/handler 的 WithRatelimit 使用。

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 退出。

func NewGCRA added in v0.3.0

func NewGCRA(rate float64, burst int, opts ...Option) *GCRA

NewGCRA 创建 GCRA 限流器。rate=每秒稳定速率,burst=可突发数(>=1)。

func (*GCRA) Allow added in v0.3.0

func (g *GCRA) Allow(key string) (bool, time.Duration)

Allow 按 key 限流(每次消耗 1)。返回是否放行,以及超限时建议的重试等待。

func (*GCRA) Stop added in v0.3.0

func (g *GCRA) Stop()

Stop 停止 gc goroutine。幂等。

func (*GCRA) String added in v0.3.0

func (g *GCRA) String() string

String 便于日志/调试。

type KeyFunc

type KeyFunc func(r *http.Request) string

KeyFunc 从请求提取限流 key(如 IP / userID)。返回空串表示不限流(跳过)。

type Limiter

type Limiter interface {
	Allow(key string) (allowed bool, retryAfter time.Duration)
}

Limiter 限流器接口。按 key 隔离(每个 key 独立计数)。 返回 (allowed, retryAfter):retryAfter=0 表示立即可重试或已放行。

func FromContext

func FromContext(ctx context.Context) Limiter

FromContext 从 ctx 取出 Limiter(没有则 nil)。

type Option

type Option func(*config)

Option 配置限流器。

func WithGcInterval

func WithGcInterval(d time.Duration) Option

WithGcInterval 设置 gc 扫描间隔。默认 1min。

func WithMaxIdle

func WithMaxIdle(d time.Duration) Option

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) Stop

func (sw *SlidingWindow) Stop()

Stop 停止 gc goroutine。幂等。

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。

func (*TokenBucket) Allow

func (tb *TokenBucket) Allow(key string) (bool, time.Duration)

Allow 按 key 限流。返回是否放行,以及建议的重试等待(超限时)。

func (*TokenBucket) Stop

func (tb *TokenBucket) Stop()

Stop 停止 gc goroutine。幂等。

func (*TokenBucket) String

func (tb *TokenBucket) String() string

String 便于日志/调试。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL