分布式锁课题
分布式锁概念
解决分布式服务下,多线程环境对同一份资源竞争的数据安全性,分布式锁是 用于保证整个集群内的多线程并发线程安全性的一种手段
分布式锁特征
高性能、可重入、防死锁和互斥性
-
高性能:最求高QPS
-
可重入:当一次请求的代码中包含两个锁时,并且递归调用两个锁时,要保证可重入,否则会出现死锁 ,重入几次就要释放几次
public synchronized void test1() {
// 阻塞卡死了
test2();
}
public synchronized void test2() {
test1()
}
-
防死锁 除上面的情况下,如果加锁后服务器宕机,锁不释放也会产生死锁
-
互斥性
实现分布式锁的方式
- Mysql 性能低下,通过insert时的唯一索引实现
- redis 可以通过setNx方法实现,这个是最简单的分布式锁,比如执行一个方法时,加一个锁,且不设置过期时间,或者设置一个很大的过期时间,但是有弊端,对于业务量不高也可以使用 另外一种就是使用redission框架,这个安全性更高
- zookeeper 该锁最安全,但是成本有点大,因为还要引进zookeeper
使用场景
- 保证接口的幂等,防止重复提交,这个时很高频的使用
- 分布式的任务调度,分布式的系统可能多个执行器执行定时任务,防止任务重复执行,使用分布式锁,这个在我执行实现的任务调度中也使用过
- 防止超卖的情况 这个实际工作中我也遇到过,做过抢单业务都会遇到此种情况
使用redis实现分布式锁特性
- 原子性 由于redis的设置分布式锁,需要两个命令
- 设置key value
- 设置过期时间 即便使用setNx方法,底层也是两个命令 setNX item-4 111 set item-4 111 EX 20 如果第一个命令执行成功了,第二个失败了,那么就没有了过期时间,照成死锁,就不具备原子性,要么都成功,要么都失败,所以要通过使用lua脚本来解决
-
过期时间 上面说了,没有过期时间可能会出现死锁的情况
-
锁续期 如果一个业务锁到了过期时间但是业务没有执行完,就会造成锁失效,没有锁住,这部分的解决方案就是通过watchdog来实现
-
正确释放锁 A上的锁被B释放了,这样就会造成错误释放锁,原因是A与B的key值是相同的,所以要注意key值
使用redis实现分布式锁的部署方式
- 单机 简单,但是风险大
- 哨兵 主从 如果mater挂掉,又没同步到slave会导致,锁丢失
- 集群 虽然是集群但是,也是部署在集群中其中一台机器上,挂掉就没了
- 红锁 全都是master,但是性能低,成本高
redission实现分布式锁
加锁
解锁
watchdog锁续期
转载自:https://juejin.cn/post/7197756464366829629