场景

1.服务A 与 服务B 都希望拿到锁

Redis获取锁发起命令: SET productId:lock xxx2312xxxx NX EX 3000
productId 可以自定义的,与业务有关的ID
:lock 也就是锁的意思,也可以放到业务ID前面
xxx2312xxxx 随机生成的唯一字符串,必须保证全局唯一
NX 如果 productId:lock 在redis中不存在,则返回成功,否则失败
EX 设置过期时间,时间到了则删除key

2.服务B为了获取锁也向Redis发送相同的命令SET productId:lock xxx4444xxxx NX EX 3000

执行命令发现Redis已经存在了productId这个key,并且没有过期,因此执行命令失效,服务B获取锁失败
而后服务B进入循环请求状态,比如每隔一秒(自定义秒数)往Redis发送请求,直到成功并获得锁

3.服务A的业务代码比较多执行时间超过了你设置的30秒,那么你在Redis存的productId:lock这个key则会过期

过期之后自动删除了这个key,因此服务B则发送命令成功获取到锁;
当然也可以直接失败告诉用户,重新再试,就不会导致一直请求;
Ps: 出现这种问题解决方案应该是给服务A的key进行过期时间的延续(watch dog);

4.服务A执行完开始释放锁,服务A会主动向Redis发送删除key的命令

如果服务A的key过期了,但是删除key的命令还没发起
此时服务B发起获取锁的命令并且获取到了,但是服务A发起了删除Key的命令
导致了服务A将服务B的key直接删除了
解决方案:这时候服务A获取Redis的锁拿到value根据与生成的唯一字符串也就是xxx2312xxxx来判断是否一致
一般使用Lua脚本:

1
2
3
4
5
if redis.call("get", KEYS[1])==ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end

死锁

1.加锁但是不释放锁,导致其他程序加锁永远都加不上锁,也就造成了死锁,需要进行锁释放,删除redis的key
2.加锁但是程序没有执行释放锁,因为程序挂了,那么可以使用redis的过期时间