【问题标题】:Redis - max count of records with a key pattern that can expireRedis - 具有可以过期的键模式的最大记录数
【发布时间】:2014-10-26 08:38:29
【问题描述】:

假设我们是销售 T 恤的在线卖家。我们只剩下 1 件 T 恤可以出售。不完整的订单被放置在 redis 中,它们会在 1 小时内自动过期。我们不能卖出超过 1 件剩余的 t-shirt,所以我们必须将 redis 中的挂单 key 数量限制为 1。如果订单完成,redis 中的临时订单将被删除,并将完成的订单写入用于履行的数据库。

如果客户来了,我们必须检查剩余的库存量(在我们的示例中是 1 件 T 恤)以及 redis 中已经存在多少待处理订单(到期前),以及是否没有可用的要出售的库存,如果我们没有足够的库存(在我们的假设示例中为 1 件 T 恤),我们将不允许订购该 T 恤。

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

  1. 客户 A 来访。如果存在挂单,请检查 redis - 扫描“order:t_shirtid:1”。不存在。
  2. 开始交易 - watch "order:t_shirtid:1", multi, setex "order:t_shirtid:1" 3600 1, exec
  3. 如果客户 B 访问,我们将看到一个挂单,其键“order:t_shirtid:1”的值为 1,并且不允许客户 B 下单
  4. 如果 1 小时后,key“order:t_shirtid:1”过期且未完成,客户 B 访问时会看到 redis 中没有该 key,可以继续订购

这个策略有时会失败,因为客户A和客户B可能会去不同的应用服务器,都发现redis中没有“order:t_shirtid:1”的东西,都会准备顺序写入redis(即手表不会有任何影响,因为,首先客户 A 去,完成所有事情,然后客户 B 进入 redis 并写入相同的东西,但更重要的是,两者都已经完成了对“order:tshirt_id:1”的扫描,知道有redis 中没有挂单)。因此,即使只剩下 1 件 T 恤可供出售,我们也允许客户下订单。

那么,处理这个用例的正确方法是什么。我有兴趣了解其他人所做的事情。提前感谢您的帮助。

【问题讨论】:

    标签: redis


    【解决方案1】:

    由于您使用的是 WATCH/MULTI/EXEC,因此只有在 A 完成(执行)事务后 B 开始事务时,才会发生竞争条件。

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

    顺便说一句,从您的示例看来,给定 t_shirt ID 的临时订单不能超过一个。

    【讨论】:

    • 谢谢。你说的对。 B 必须在 A 执行后开始。手动到期是我想避免的,因为这是在应用程序中跟踪的另一件事。有没有更好的 Lua 脚本处理方式?
    • 当然 - 逻辑完全支持 Lua。请参阅(唯一的)Josiah Carlson 提供的类似方法的答案(虽然它是在 Python 中,但对 Lua-fy 来说应该是微不足道的):groups.google.com/d/msg/redis-db/-evvmnNWeaI/4GMSHgeixvEJ
    • 再次感谢!最后一个问题。我们将如何定期进行?我们是否必须扫描特定模式的每个键(如“order:tshirts:”)并在此之后使用 ZREMRANGEBYSCORE?另外,如何防止将第二件 T 恤添加到“order:tshirts:”排序集中?我们应该先在事务中检查它的大小吗?但是在事务中,我们是否能够首先获得大小来决定是否向集合中添加新的东西?对不起,如果这个问题看起来很幼稚 - 我对 redis 很陌生
    • 就个人而言,我更喜欢在每次触摸相关键后执行此操作,因此在您的情况下,每当您将新订单添加到项目的排序集中时,请执行 ZREMRANGEBYSCORE。 IMO,这比定期(例如 cron)运行清理作业更可取。至于在事务中检查它,当然 - 只需在开始时观察密钥,读取相关成员,然后启动 MULTI 块 - 如果密钥更改,EXEC 将失败。更新 - 没有问题,我们在某个阶段都是新的;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-12
    • 1970-01-01
    • 2015-12-18
    • 2022-02-07
    • 2018-04-20
    • 1970-01-01
    相关资源
    最近更新 更多