一个常用的做法是,通过一个集中式的 data store 来维护配额信息。服务收到请求时,向 data store 申请额度,如果还有额度就可以提供服务,否则就拒绝。实现过程要注意多个服务同时申请配额时带来的 竞争状态(race condition)。一般 get-then-set 容易出现这种问题,换成 set-then-get 是比较好的,通过 set 过程的原子操作来保证该节点申请到了配额。使用 Redis 时可以用其 Lua 脚本,即可以揉入计算逻辑(比如令牌桶的计算),也可以保证执行过程原子化。
集中式 data store 的问题在于:
查询配额过程 会增加延迟。优化方法是,可以批量申请配额,在服务节点本地做配额是否足够的判断,这样不用每次都查询 data store
Data store 故障时影响限流功能。服务的实现中应该做容灾,在 data store 故障时放行所有请求