用redis实现洪水控制

时间:2015-12-30 21:21:38

标签: php drupal redis

我正在尝试用基于redis的实现替换Drupal 8的泛洪控制服务的sql实现。

请参阅https://github.com/drupal/drupal/blob/8.0.x/core/lib/Drupal/Core/Flood/DatabaseBackend.php

要求是这样的:

  • 每次出现的操作/事件(例如尝试登录)都会记录到期,标识符和时间戳
  • 我需要能够防止在给定的时间范围内某项行动超过N次
  • 我希望能够清理已过期的活动
  • 在10分钟内阈值为3的情况下,如果用户尝试一次,然后在5分钟后尝试两次,则他被阻止并且可以在再过5分钟后再次尝试一次。不是10.虽然第二种方法是一种有效的方法,但不是sql实现的工作方式或测试期望它如何工作。
  • 正如您所见,基于API,我也不知道何时注册事件的阈值是什么,我只知道单个事件的到期时间。

我对如何实现这一点的想法:

  • 如果在N次出现之后应该锁定给定时间,那么使用单个KEY for event会很容易:增加的标识符,一旦达到最大值,它将被锁定直到它再次到期并且每个INCR将还会更新到期日期(或不更新)。
  • 我发现很多帖子询问列表条目是否过期,这是不可能的。有使用排序集的变通方法和按范围删除。大多数似乎使用单个全局集,但我不能轻易计算我的事件+标识符 - 我认为。

写下这一切之后,我可能真的知道它是如何工作的,所以我想我正在寻找的是关于这是否有意义或是否有更简单的方法的反馈。

每个事件:标识符组合是一个键并包含一个有序集。它使用到期作为分数,并将值用作唯一值,可能是以微秒为单位的创建时间。我计算未过期的记录以检测是否达到阈值。我正在更新每个事件的到期时间:标识符到提供的到期时间窗口,因此除非给定的标识符/客户端不放弃并继续尝试,否则它将被自动删除,而不会达到过期时间。是否值得清理一组内的记录,例如在做新注册时?它似乎相当快,我有时也只能这样做。

1 个答案:

答案 0 :(得分:1)

我更愿意使用Redis的密钥过期功能,而不是重新实现一个。

更简单的替代方案是:

  • 只需设置一个简单的值,即尝试的次数;使用基于“标识符”之类的模式构建的键:“事件类型”: SETNX <identifier>:<event type> 1
  • 如果响应为1,这是第一次尝试,因此您在此键上设置超时: EXPIRE <identifier>:<event type> <timeout in seconds>

  • 否则您会增加尝试次数 INCR <identifier>:<event type> INCR的响应将为您提供窗口期间的尝试次数,因此您知道是否允许该操作。

如果需要存储更多数据(如给定时间窗口中允许的最大尝试次数),您还可以使用哈希而不是简单值。在这种情况下,您可能会使用HSETNX和HINCR。