Skip to content

Fix atomic multi-dimension rate limiting#39

Open
isCharles wants to merge 1 commit into
Snailclimb:masterfrom
isCharles:ischarles/rate-limit-atomic-dimensions
Open

Fix atomic multi-dimension rate limiting#39
isCharles wants to merge 1 commit into
Snailclimb:masterfrom
isCharles:ischarles/rate-limit-atomic-dimensions

Conversation

@isCharles

@isCharles isCharles commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Execute all @RateLimit rules for a method in a single Redis Lua call.
  • Split the Lua logic into a check phase and a deduct phase so no dimension is charged unless every rule passes.
  • Keep the failed-rule mapping so fallback/error handling still points at the dimension that rejected the request.

Root cause

The previous aspect loop called the Lua script once per @RateLimit rule. If an earlier rule such as GLOBAL succeeded and a later rule such as IP failed, the rejected request had already consumed the global token.

Validation

  • .\gradlew.bat :app:compileJava :app:compileTestJava
  • .\gradlew.bat :app:test --tests "interview.guide.common.aspect.RateLimitScriptTest"

Note: RateLimitIntegrationTest remains disabled because it requires a live Redis instance, but its multi-rule case now asserts that a later rejected dimension does not deduct earlier dimensions.

之前 RateLimitAspect 会按 @RateLimit 规则逐条循环调用 Lua 脚本。如果前面的规则,例如 GLOBAL,已经扣减成功,但后面的规则,例如 IP,限流失败,那么这次请求虽然最终被拒绝,却已经消耗了全局令牌。

如果有人疯狂刷接口,即使这些请求最终都被 IP 限流拒绝,也可能持续消耗 GLOBAL 令牌。结果是其他正常用户更早遇到全局限流。统计上也有问题。

更改

  • 将同一个方法上的所有 @RateLimit 规则合并到一次 Redis Lua 调用中执行。
  • Lua 脚本拆成两个阶段:先检查所有限流维度是否都有足够令牌,全部通过后再统一扣减。
  • 保留失败规则的映射关系,因此 fallback 或错误处理仍然能准确指向触发限流的维度。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant