假设我们是销售T恤的在线销售商。我们只剩1件T恤待售。不完整的订单放在redis中,它们会在1小时内自动过期。我们不能卖超过1件剩余的T恤,所以我们必须将redis中的挂单数量限制为1.如果订单完成,redis中的临时订单将被删除,并且已完成的订单将被写入实现数据库。
如果客户来了,我们必须检查剩余的库存量(在我们的示例中,它是1件T恤)以及redis中已经有多少挂单(到期前),如果没有如果我们没有足够的库存(在我们的假设示例中有1件T恤),我们将不会允许订购T恤。
这是我的第一次尝试(我第一次使用redis - 主要是因为redis可以自动过期我们在任何数据库中都不需要的挂起键。)
这种策略有时会失败,因为客户A和客户B可能会转到不同的应用服务器,两者都发现redis中没有“order:t_shirtid:1”,两者都准备按顺序写入redis(即手表)将没有任何效果,因为,第一个客户A去,完成所有事情,然后客户B进入redis并写相同的东西,但更重要的是,两个人已经完成扫描“order:tshirt_id:1”一个接一个地知道有redis中没有挂单)。因此,即使只剩下1件T恤,我们也只是让客户下订单。
那么对于这个用例来说是正确的方法。我有兴趣了解别人的所作所为。在此先感谢您的帮助。
答案 0 :(得分:0)
由于你正在使用WATCH / MULTI / EXEC,只有在A完成(执行)它之后B才开始交易时才会出现竞争条件。
IMO,解决此问题的更好方法是将临时订单存储在已排序的集合中。这将允许您使用原子Redis操作替换SCAN并将其包含在事务的流程中,从而消除竞争条件(以及提高性能)。但是,如果采用这种方法,则需要手动使ZSET成员过期(使用分数来存储时间戳,定期/在访问时删除1小时的成员)。
BTW,从您的示例来看,对于给定的t_shirt ID,它看起来不仅仅是一个临时订单。