【发布时间】:2015-11-05 12:19:31
【问题描述】:
我有一个用于 B2B 应用程序的 Web 应用程序,该应用程序具有多个同类 Web 前端(具体来说,我在 App Engine 上运行)。我需要设计一个短期配额系统,以便在客户的突发请求率超过其配额时拒绝流量。需要支持的客户数量在数万范围内。我想衡量这些配额的时间范围将在“分钟”范围内;最多一个小时。
例如如果时间尺度是 10 分钟,并且客户 X 提出的请求远远超过了他们的配额,那么我可以让系统为他们的 所有 请求提供服务,直到他们用完每 10 次允许的请求数量分钟,然后拒绝他们在该 10 分钟窗口剩余时间内的所有请求,然后在接下来的 10 分钟窗口中重新开始该过程。
我考虑过的半生不熟的解决方案:
买一个强大的 Redis 盒子。在来自客户 X 的每个请求(或者可能是其中的某个固定百分比,例如 1-in-10,以减轻负载)时,将 GET 设置为 X 计数变量。如果 > 他们的每 10 分钟配额,则拒绝该请求。否则,对 count-of-X 变量进行 INCR 并为请求提供服务。每 10 分钟,将所有客户的计数设置为 0。
与上面类似,除了使用 memcache,因为该服务内置在应用引擎中,所以我不需要运行自己的盒子。如果 memcache 值丢失了,哦,好吧——我们可能不会在那个时间窗口内像我们应该的那样节流(只要时间窗口足够短,我们可能不会太在意)。
每个网络服务器都存储全球每个客户的计数器,用于 new-requests-seen-by-me 和 requests-seen-globally。每一秒(左右),每个网络服务器都会将其 new-requests-seen-by-me 值(针对每个客户)推送到某个集中的类似 pub-sub 的服务,该服务将该值重新分配给所有网络服务器(它们添加到他们的 requests-seen -全球价值)。 Web 服务器使用他们的 requests-seen-globally 值(总是有点陈旧)来决定是服务还是拒绝请求。
【问题讨论】:
-
多少流量?大多数人只需将计数器保存在数据库中就可以了。但是,如果您预计每分钟有数百万个请求,您可能需要做一些更聪明的事情......
-
呃——抱歉。显而易见的事情要省略。对于我在这里关注的特定类型的请求,我们预计某些客户将产生高达 50/秒的请求。这对于应用引擎数据存储来说太高了(它只支持对单个实体的约 5 次写入/秒的速率),但肯定可以通过 Redis 或 Cassandra 之类的东西来管理。
-
然后我会使用内存缓存。它会工作得很好。如果它是 Redis 或 memcache 的一个偶数选择,我会选择 Redis,但一个更容易。选项#3 适合严重的规模。您没有考虑的一个选项是让负载平衡器将用户与服务器联系起来。这简化了这一点,因为现在服务器应该知道所有用户请求。并且可以保持其他类型的用户状态。