【问题标题】:Redis: How to ensure both concurrency and atomic for shopping case?Redis:如何确保购物案例的并发性和原子性?
【发布时间】:2015-11-14 03:49:39
【问题描述】:

假设food_dictdictionary 将商品存放在购物车中,

{<food_id>:<count>}

一个购物车可能包含多种食物

我已经提前将food存储在redis中:

r.hset('food:<food_id>', {'price': <price>, 'stock': <stock>})

在对cart下订单时,我必须确保stock大于count

基本工具:

for k,v in food_dict.iteritems():
    _stock = int(redis_db.hget('food:' + str(k), 'stock'))
    if v > _stock:
       # I have to rollback the decrement of stock
       break
    else:
       redis_db.hset('food:' + str(k), 'stock', _stock - v)

需要rollbackpipeline

    pipe = redis_db.pipeline()
    for k, v in food_dict.iteritems():
        _stock = int(redis_db.hget('food:' + str(k), 'stock'))
        if v > _stock:
            return
        else:
            pipe.hset('food:' + str(k), 'stock', _stock - v)
    pipe.execute()

对于单个客户端,上面的代码可以做得很好。在并发方面:

with redis_db.pipleline() as pipe:
    while 1:
        try:
            pipe.watch(['food:' + str(k) for k in food_dict])
            stock_dict = {}
            for k in food_dict:
                _stock = pipe.hget('food:' + str(k), 'stock')
                stock_dict[k] = _stock
            pipe.multi()
            for k, v in food_dict.iteritems():
                if v > stock_dict[k]:
                    break
                else:
                    pipe.hset('food:' + str(k), 'stock', stock_dict[k] - v)
            pipe.execute()
            break
        except WathchError:
            continue
        finally:
            pipe.reset()

此代码能否保证只有当库存大于数量时才能下订单

【问题讨论】:

    标签: python concurrency transactions redis


    【解决方案1】:

    是的,pipe.execute() 应该在任何被监视的键​​被更改时出错。

    但是。 WATCH/MULTI/EXEC 模式允许您实现乐观锁定,并且您的事务越长,它们就越有可能失败。此外,鉴于食品库存柜台很“热”,我认为这种方法在您的用例中无效。

    相反,我会将交易实现为 Lua 脚本,该脚本首先检查每件商品的库存。然后我可以在该脚本中决定是否提交购物车中的一些订单,全部提交,不提交或其他任何订单。

    编辑

    只用python如何更有效的热购?

    我猜你只能使用 Python 来做一些小的优化。核心区别在于,现在您正在管理应用程序中的“事务”,因此当存在并发时,它更有可能回滚。 Lua 允许您在服务器上执行 tx 的逻辑,因此您基本上锁定了所有内容,但 tx 会成功(只要启动后有足够的食物库存)。

    至于次要优化,现在看起来food:* 是一个哈希键,它存储了除stock 之外的其他内容 - 如果其中任何信息也发生变化,它将回滚正在运行的事务。您可以考虑为每种食品使用专用的库存密钥(例如food:apples:stock)并观看它。

    由于您尝试提交整个购物车,也许您还应该考虑将其拆分为多个事务 - 一个用于购物车中的每个项目。这意味着如果您决定完全中止,您的应用程序将负责重试热门项目并回滚已提交的更改,这对于购物车通常是可以接受的(想想有多少次您看到产品留在购物车中或附近杂货店的收银员)。

    附: Lua 和 Python 非常相似,所以我真的鼓励你去学习它。这很有趣、简单而且非常值得,因为您已经在使用 Redis...

    【讨论】:

    • 如何让hot 只用python 购物更有效?
    • 已编辑答案作为回应。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多