Redis - 具有可以过期的密钥模式的记录的最大计数

时间:2014-09-02 06:43:30

标签: redis

假设我们是销售T恤的在线销售商。我们只剩1件T恤待售。不完整的订单放在redis中,它们会在1小时内自动过期。我们不能卖超过1件剩余的T恤,所以我们必须将redis中的挂单数量限制为1.如果订单完成,redis中的临时订单将被删除,并且已完成的订单将被写入实现数据库。

如果客户来了,我们必须检查剩余的库存量(在我们的示例中,它是1件T恤)以及redis中已经有多少挂单(到期前),如果没有如果我们没有足够的库存(在我们的假设示例中有1件T恤),我们将不会允许订购T恤。

这是我的第一次尝试(我第一次使用redis - 主要是因为redis可以自动过期我们在任何数据库中都不需要的挂起键。)

  1. 客户A访问。如果挂单存在,请检查redis - 扫描“order:t_shirtid:1”。没有。
  2. 开始交易 - 观看“order:t_shirtid:1”,multi,setex“order:t_shirtid:1”3600 1,exec
  3. 如果客户B访问,我们将看到一个挂单,其中包含“order:t_shirtid:1”键,值为1且不允许客户B订购
  4. 如果在1小时后,密钥“order:t_shirtid:1”到期且尚未完成,客户B在访问时将看到该密钥没有任何内容可以继续订购
  5. 这种策略有时会失败,因为客户A和客户B可能会转到不同的应用服务器,两者都发现redis中没有“order:t_shirtid:1”,两者都准备按顺序写入redis(即手表)将没有任何效果,因为,第一个客户A去,完成所有事情,然后客户B进入redis并写相同的东西,但更重要的是,两个人已经完成扫描“order:tshirt_id:1”一个接一个地知道有redis中没有挂单)。因此,即使只剩下1件T恤,我们也只是让客户下订单。

    那么对于这个用例来说是正确的方法。我有兴趣了解别人的所作所为。在此先感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

由于你正在使用WATCH / MULTI / EXEC,只有在A完成(执行)它之后B才开始交易时才会出现竞争条件。

IMO,解决此问题的更好方法是将临时订单存储在已排序的集合中。这将允许您使用原子Redis操作替换SCAN并将其包含在事务的流程中,从而消除竞争条件(以及提高性能)。但是,如果采用这种方法,则需要手动使ZSET成员过期(使用分数来存储时间戳,定期/在访问时删除1小时的成员)。

BTW,从您的示例来看,对于给定的t_shirt ID,它看起来不仅仅是一个临时订单。