一个秒杀的例子
最简单的例子
1. 最基础的
add lock
....逻辑代码
del lock
在这个情况有有几个bug。 代码执行的过程中出错了,导致死锁了
2. 在1的基础上修改
add lock (加个过期时间,需要设置lock和设置过期时间在一行命令下完成,不然可能会有问题)
....逻辑代码
del lock
补充说明:
Redis的setnx命令是当key不存在时设置key,但setnx不能同时完成expire设置失效时长,不能保证setnx和expire的原子性。但是可以使用set命令完成setnx和expire的操作,并且这种操作是原子操作。
set key value [EX seconds] [PX milliseconds] [NX|XX]
EX seconds:设置失效时长,单位秒
PX milliseconds:设置失效时长,单位毫秒
NX:key不存在时设置value,成功返回OK,失败返回(nil)
XX:key存在时设置value,成功返回OK,失败返回(nil)
举例说明:set name thisismyname ex 20 nx => 可以ttl name 看有多少时间
在这种情况下,可能设置的过期时间为10,但是程序A总共需要执行15秒,在第10秒的时候,自动失效了。此时有另外一个程序B共需要执行8秒(获取锁了),在第15秒时,A把B的锁给删了
3. 在2的基础上修改
add lock (加个过期时间)
....逻辑代码
del lock (删除自己的锁)
在删除之前判断一下,锁是不是自己的,用redis的hash看锁的uuid是不是自己的。
释放锁的操作必须使用Lua脚本来实现。释放锁其实包含三步操作:’GET’、判断和’DEL’,用Lua脚本来实现能保证这三步的原子性。
这时还是有问题,就是锁过期了,程序还没执行完。需要有个策略能让锁自己续时间(用watch dog ,todo)
4.非单机情况下的锁
如果3完成了,还有问题,因为上面1~3都是单机环境下执行的,没什么问题。如果是redis的主从或者集群模式下,锁在master上,还没同步,突然master挂了,这是slave会顶上去,但是slave上还是没有锁的,这是其它程序又能获取锁了。在这种情况下,需要有个策略(用redlock,todo)。其实网上不推荐用redlock,推荐用zookeeper保证强一致性。
以上部分都没问题后,关于分布式锁应该就没什么大问题了~
网友评论