Redis:如何确保购物案例的并发性和原子性?

时间:2015-11-14 03:49:40

标签: python concurrency transactions redis

假设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)

rollback,需要pipeline

    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()

此代码是否可以保证订单只有在库存大于时才能

1 个答案:

答案 0 :(得分:1)

是的,如果更改了任何已观看的密钥,pipe.execute()会出错。

然而。 WATCH/MULTI/EXEC模式允许您实现乐观锁定,事务处理时间越长,它们就越有可能失败。此外,鉴于食品库存柜台很热,我不认为这种方法对您的使用情况有效。

相反,我会将事务实现为Lua脚本,首先检查每个项目的库存。然后我可以在那个剧本中决定是否提交购物车中的一些订单,所有订单,没有订单或其他任何订单。

修改

  

如何更有效地使用python进行热购物?

我猜你只能使用Python进行小的优化。核心区别在于,您现在正在管理&#34;交易&#34;在应用程序中,所以当有并发性时,它更有可能回滚。 Lua允许您在服务器上执行tx的逻辑,因此您基本上锁定了所有内容,但tx将成功(只要一旦启动就有足够的食物库存)。

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

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

P.S。 Lua和Python非常相似,所以我真的鼓励你去接受它。它既有趣又简单,非常值得,因为您已经在使用Redis ......