我正在创建 API 限制器,但在决定使用哪个系统进行数据存储时遇到了问题。
很明显,我将需要一个 volatile 存储,以及一个持久性存储。
在 volatile 上,我想像这样存储一个键值:
read:14522145 100
read:99885669 16
read:78951585 100
这是一个由以下组成的 key :{action}:{client}
和一个整数值(可用积分)。
在持久化上,我想保留所有资源中断的记录。
算法(伪代码)非常简单:
MAX_AMOUNT = 100
call(action, client, cost) {
key = action + ":" + client
if (volatileStorage.hasKey(key)) {
value = volatileStorage.getValue(key)
if (value >= cost) {
volatileStorage.setValue(key, value - cost)
return true
} else {
persistentStorage.logOutage(method, client, cost)
return false
}
} else {
volatileStorage.setValue(key, MAX_AMOUNT)
return call(action, client, cost)
}
}
有一个并行进程每 N
运行一次每个 method
秒, 这会增加所有键 {action}:*
从 M 到 O。
此外,我想从 volatile 存储中删除所有早于 P 秒(自此未修改)的项目。
所以基本上每个 Action 都是action<N, M, O, P>
.例如,阅读用户每 1 秒增加 5 个点,最多 100 个,并在 60 秒不活动后删除:read_users<1, 5, 100, 60>
.
所以我需要一个 volatile 存储:
- 读取速度非常快,不会消耗太多资源(如果进程比自己调用的成本更高,那么拒绝调用有什么意义)。
- 允许对项目进行 TTL。
- 可以在不超出定义限制的情况下,以良好的性能增加所有匹配模式 (
read_users:*
) 的键。
和持久存储:
- 也很快。
- 可以处理大量寄存器。
欢迎提出任何建议。
最佳答案
这不是答案,而是一种观点:您最好使用现有的速率限制器,而不是自己制作。正确实现是很棘手的,因此采用经过生产验证的实现不仅更容易,而且更安全。
例如,Generic cell rate algorithm简直就是魔法,有几个 Redis 实现,包括:
- 作为 Ruby gem(使用服务器端 Lua):https://github.com/rwz/redis-gcra
- 作为 (v4) 模块:https://github.com/brandur/redis-cell/
当然,还有更多基于 Redis 的速率限制器 - 我使用 Google 找到它们;)
关于mongodb - 基于用例的数据库技术选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43591677/