为什么需要分布式锁
当一个成员变量有可能同时(并发)被多个服务或者多个线程同时访问,导致最终数据不一致。
例如库存只有1件商品,三个用户通过三台订单服务同时下单成功,导致库存错误。
分布式锁应具备哪些条件
-
分布式环境下,一个方法在同一时间只能被同一台机器的同一线程执行。
-
高可用、高性能的获取锁、释放锁
-
具备锁失效机制,防止死锁
-
具备非阻塞锁特性
Zookeeper实现原理
利用Zookeeper的顺序临时节点,实现分布式锁和等待队列,Zookeeper是为了解决分布式锁而诞生。
分布式锁常见的实现方式
redis实现分布式锁
原理
- redis 通过 set或者setnx 方法设置key
- 如果返回成功,表示未加锁,可以访问资源
- 如果返回失败,表示已加锁,等待解锁
- redis过期自动释放资源
set foo.log 1 ex 10 nx
#一顿操作
del foo.log
#或者
setnx foo.log 1
expire 10
#一顿操作
del foo.log
致命问题
-
非原子性操作,如果使用setnx后宕机,没有设置 expire。则导致死锁。
解决方案:2.6 以上版本可以使用 set 进行原子性操作。
-
误删除锁
- 如果进程1执行时间超过锁释放时间,redis自动删除锁
- 新的进程(进程2)加锁
- 进程1执行结束, 删除 进程2 锁
解决方案:校验锁是否为当前进程添加的。
set key value , 把value设置为进程id
- 判断任务是否完成
增加守护进程,如果任务没有完成每隔一段时间续期。