说起分布式锁,我们都知道基本的三种实现方式:
1、基于数据库(唯一索引) 2、基于Zookeeper
3、基于缓存(Redis,memcached,tair)
下面我们来逐一讲解下几种分布式锁的实现:
一、基于数据库(唯一索引)
基于数据库实现分布式锁主要是利用数据库的唯一索引来实现,唯一索引天然具有排他性,这刚好符合我们对锁的要求:同一时刻只能允许一个竞争者获取锁。
加锁时我们在数据库中插入一条锁记录,利用业务id进行防重。当第一个竞争者加锁成功后,第二个竞争者再来加锁就会抛出唯一索引冲突,如果抛出这个异常,我们就判定当前竞争者加锁失败。
防重业务id需要我们自己来定义,例如我们的锁对象是一个方法,则我们的业务防重id就是这个方法的名字,如果锁定的对象是一个类,则业务防重id就是这个类名。
二、基于Zookeeper
zookeeper 可以根据有序节点+watch实现,实现思路,如:
为每个线程生成一个有序的临时节点,为确保有序性,在排序一次全部节点,获取全部节点,每个线程判断自己是否最小,如果是的话,获得锁,执行操作,操作完删除自身节点。如果不是第一个的节点则监听它的前一个节点,当它的前一个节点被删除时,则它会获得锁,以此类推。
三、基于Redis
1、setnx方式(如何解决与Expire的原子性?)
2、SET key value [EX seconds] [PX milliseconds] [NX|XX]
EX second :设置键的过期时间为second秒(✔️)
PX millisecond :设置键的过期时间为millisecond毫秒
NX :只在键不存在时,才对键进行设置操作(✔️)
XX:只在键已经存在时,才对键进行设置操作
SET操作成功完成时,返回OK ,否则返回nil
必须注意,为了解铃还需系铃人,value建议取uuid
3、可重入如何解决(threadLocal?AQS?)
4、业务超时如何解决(redisson?)