赞
踩
Redis 分布式锁使用 SET 指令就可以实现了么?在分布式领域 CAP 理论一直存在。分布式锁的门道可没那么简单,我们在网上看到的分布式锁方案可能是有问题的。
楼主将一步步带你深入分布式锁是如何一步步完善,在高并发生产环境中如何正确使用分布式锁。
分布式锁其实就是,控制分布式系统不同进程共同访问共享资源的一种锁实现的方式,如果不同的系统或者同一个系统的不同主机之间共享了某个临界资源,往往需要互斥来防止彼此干扰,以保证一致性
但是使用这个方案要注意 setnx 与 expire 之间的原子性操作,如果在执行完 setnx 之后服务器 crash 或重启了导致加的这个锁没有设置过期时间,就会导致死锁的情况(别的线程就永远获取不到锁了)
SETNX 是 SET IF NOT EXISTS 的简写.日常命令格式是 SETNX key value,如果 key 不存在,则
SETNX 成功返回 1,如果这个 key 已经存在了,则返回 0。
假设某电商网站的某商品做秒杀活动,key 可以设置为 key_resource_id,value 设置任意值,伪代码如下:
但是这个方案中,setnx 和 expire 两个命令分开了,「不是原子操作」。如果执行完 setnx 加锁,正要执行 expire 设置过期时间时,进程 crash 或者要重启维护了,那么这个锁就“长生不老”了,「别的线程永远获取不到锁啦」。
把过期时间放在 setnx 的 value 里面,如果加锁失败,再拿出 value 值校验一下即可。
加锁代码:
这个方案的优点是,巧妙移除 expire 单独设置过期时间的操作,把「过期时间放到 setnx 的 value 值」里面来。解决了方案一发生异常,锁得不到释放的问题。但是这个方案还有别的缺点:
实际上,我们可以使用 Lua 脚本来保证原子性(包含 setnx 和 expire 两条指令)
lua 脚本如下:
加锁代码如下:
String lua_scripts = "if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then" +
" redis.call('expire',KEYS[1],ARGV[2]) return 1 else return 0 end";
Object result = jedis.eval(lua_scripts, Collections.singletonList(key_resource_id), Collections.singletonList(values));
//判断是否成功
return result.equals(1L);
除了使用 Lua 脚本,保证 SETNX + EXPIRE 两条指令的原子性,我们还可以使用 Redis 的 SET 指令扩展参数(SET key value [EX seconds] [PX milliseconds] [NX|XX]),它也是原子性的。
SET key value[EX seconds][PX milliseconds][NX|XX]
既然锁可能被别的线程误删,那我们给 value 值设置一个标记当前线程唯一的随机数,在删除的时候,校验一下。
伪代码如下:
在这里,「判断是不是当前线程加的锁」和「释放锁」不是一个原子操作。如果调用 jedis.del()释放锁的时候,可能这把锁已经不属于当前客户端,会解除他人加的锁。
为了更严谨,一般也是用 lua 脚本代替。lua 脚本如下:
方案五还是可能存在**「锁过期释放,业务没执行完」**的问题。有些小伙伴认为,稍微把锁过期时间设置长一些就可以啦。其实我们设想一下,是否可以给获得锁的线程,开启一个定时守护线程,每隔一段时间检查锁是否还存在,存在则对锁的过期时间延长,防止锁过期提前释放。
当前开源框架 Redisson 解决了这个问题。我们一起来看下 Redisson 底层原理图吧:
只要线程一加锁成功,就会启动一个 watch dog 看门狗,它是一个后台线程,会每隔 10 秒检查一下,如果线程 1 还持有锁,那么就会不断的延长锁 key 的生存时间。因此,Redisson 就是使用 Redisson 解决了「锁过期释放,业务没执行完」问题。
前面六种方案都只是基于单机版的讨论,还不是很完美。其实 Redis 一般都是集群部署的:
如果线程一在 Redis 的 master 节点上拿到了锁,但是加锁的 key 还没同步到 slave 节点。恰好这时,master 节点发生故障,一个 slave 节点就会升级为 master 节点。线程二就可以获取同个 key 的锁啦,但线程一也已经拿到锁了,锁的安全性就没了。
为了解决这个问题,Redis 作者 antirez 提出一种高级的分布式锁算法:Redlock。Redlock 核心思想是这样的:
简化下步骤就是:
小编整理了一整套java面试资料,有需要资料的小伙伴点击获取哦~
文章转自https://blog.csdn.net/fengyuyeguirenenen/article/details/123752418
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。