基于redis的乐观锁
转自:https://www.toutiao.com/i6503412526095532558/?tt_from=weixin&utm_campaign=client_share×tamp=1514535595&app=news_article&utm_source=weixin&iid=22004594589&utm_medium=toutiao_android&wxshare_count=1
在游戏开发中,我们有时需要实现乐观锁功能,乐观锁在数据竞争概率比较小的情况下会带来比较大的性能提升。memcached中有cas命令,用来实现check-and-set这样功能。Redis中我们可以基于Multi/EXEC/WATCH操作来实现类似的功能。
被WATCH的键会被监视,并且在事务执行前会去感知键的值是否发生了变化。如果有至少一个被监视的键在EXEC执行之前被修改了,那么整个事务都会被取消。
假如有一个用户使用购买的点数,兑换了一部分游戏内的金币,通常的操作如下,
curr_point = GET user1_point
curr_gold = GET user1_gold
curr_point -= xcurr_gold += x*100
SET user1_point curr_point
SET user1_gold curr_gold
在单个Redis客户端执行上述命令的时候没有问题,但是如果用户做了多次兑换,然后有多个Redis客户端同时在执行上述逻辑,那么用户的数据就错乱了。那如果基于Redis的WATCH和MULTI/EXEC机制,我们可以这么做,
WATCH
curr_point = GET user1_point
curr_gold = GET user1_gold
curr_point -= xcurr_gold += x*100
MULTISET user1_point curr_point
SET user1_gold curr_gold
EXEC
这样如果在执行EXEC之前,user1_point和user1_gold这两个key的值发生了变化,那么事务就会失败,否则事务执行成功。对于业务来说,就是不断的去重试上述逻辑,直到成功,这也是为什么数据冲突概率小的时候,性能很好,因为基本相当于无锁,所以称之为乐观锁。