kratos默认提供基于令牌桶的middleware.ratelimit中间件,适用于接口级速率控制;需正确配置limit与burst、自定义keyfunc实现用户级限流,grpc须用grpc.ratelimit而非http版。

用 middleware.RateLimit 中间件最直接
Kratos 默认提供了基于令牌桶算法的限流中间件,不用自己写 Redis 计数逻辑。只要在 HTTP 或 gRPC Server 的 middleware 链里加上它就行,适用于大多数场景下的接口级速率控制。
常见错误是直接套用默认配置却没改 limit 和 burst,导致实际限流效果和预期不符——比如设了每秒 10 次,但 burst=1,那突发请求立刻被拒,体验反而更差。
-
limit表示平均速率(如10.0表示每秒最多 10 个请求) -
burst是允许的瞬时峰值(必须 ≥limit,否则令牌桶无法积累) - 限流 key 默认基于
remote IP + path,不带用户身份信息;如需按用户限流,得自定义keyFunc - 被限流时返回 HTTP 429,默认响应体为空;若要返回 JSON 提示,需包装一层 error handler
自定义限流 key 时注意 keyFunc 的边界条件
当需要按 user_id 或 app_key 限流,而不是单纯按 IP,就必须提供 keyFunc。这个函数接收 *http.Request,返回字符串 key。容易踩的坑是:没判空、没处理 header 缺失、或从 JWT token 解析 user_id 时 panic。
示例中常看到直接写 r.Header.Get("X-User-ID"),但一旦 header 不存在,就得到空字符串,所有未登录用户全挤在一个 key 下被限流——这等于把限流逻辑搞反了。
- 务必对输入做非空/格式校验,比如用
strings.TrimSpace清理前后空格 - 若依赖 JWT,应在限流前完成鉴权中间件,否则
keyFunc里解析 token 可能失败 - 避免在
keyFunc中做耗时操作(如查 DB),它在每次请求路径上同步执行
gRPC 接口限流要用 grpc.RateLimit,不是 HTTP 版本
很多人复制 HTTP 限流代码到 gRPC Server,发现完全不生效——因为 Kratos 的 middleware.RateLimit 只作用于 HTTP Server。gRPC 必须显式使用 grpc.RateLimit,且参数结构略有不同:
- HTTP 版接受
rate.Limiter实例,gRPC 版则直接传limit, burst float64 - gRPC 的 key 默认是
method name,不带客户端信息;如需区分调用方,仍需传入自定义keyFunc - 被限流时返回
codes.ResourceExhausted(gRPC 状态码 8),不是 HTTP 429
混用两个中间件不会报错,但限流逻辑彼此隔离,别误以为“加了一个就全局生效”。
高并发下 Redis 后端限流慎用,优先走内存限流
Kratos 官方 rate limit 中间件默认是内存型(rate.NewLimiter),轻量高效。但有些团队看到“分布式限流”就急着切 Redis,结果引入网络延迟和连接池瓶颈,反而降低吞吐。
Redis 方案适合跨实例共享配额(比如 5 台服务共用“每小时 1000 次”),但 Kratos 原生不提供开箱即用的 Redis 限流中间件,得自己基于 redis-go + Lua 脚本实现,复杂度陡增。
- 单机足够用的场景(如后台管理接口、内部系统调用),坚持用内存限流
- 真要上 Redis,注意 Lua 脚本的原子性,别用 GET+INCR+EXPIRE 三步操作,否则并发下计数错乱
- Redis key 设计建议包含服务名、方法名、标识字段,避免 key 冲突或过期策略混乱
真正难的从来不是“怎么加上限流”,而是“哪个接口该限多少、窗口怎么设、谁该被放行”。这些没法靠中间件自动判断,得结合监控里的 95 分位响应时间、错误率、上游依赖容量来反复调优。











