为什么需要分布式锁?
- 多线程可以使用普通的本地锁这些避免多线程并发修改数据
- 分布式中是多进程,进程内部的锁,锁不住其他线程,需要分布式锁。
- 需要具备:
- 互斥:任意一个时刻,锁只能被一个线程持有。
- 高可用:锁服务是高可用的,当一个锁服务出现问题,能够自动切换到另外一个锁服务。并且,即使客户端的释放锁的代码逻辑出现问题,锁最终一定还是会被释放,不会影响其他线程对共享资源的访问。这一般是通过超时机制实现的。
- 可重入:一个节点获取了锁之后,还可以再次获取锁。
- 高性能:获取和释放锁的操作应该快速完成,并且不应该对整个系统的性能造成过大影响。
- 非阻塞:如果获取不到锁,不能无限期等待,避免对系统正常运行造成影响。
- 实现方式:
- 基于关系型数据库比如 MySQL,拍他哟,性能较差,不具备锁失败
- 基于分布式协调服务 ZooKeeper
- 通过创建子节点实现
- 基于分布式键值存储系统比如 Redis 、Etcd
最常用的是 Redis
- 加锁:
SETNX lock_key uniqueValue EX 3- 加锁成功返回 1,失败返回 0
- 超过三秒不释放自动释放,防止一个进程崩溃导致业务完全不可用
- 释放锁:通过 Lua 脚本先确定加锁人和删除人是同一个,才会删除,Lua 保证原子性
- 为了避免业务没操作完,锁就过期的问题,可以通过优雅的续期,避免问题,通常异步检查
- 可重入锁就是在加锁的时候判定一下已经持有了,就不用获取了(一般框架提供了)
- 对于 Redis 集群,只要一半以上枷锁成功,就算加锁成功了
