分布式锁


1,基于数据库表实现
机制:在数据库中创建一个表,表中包含方法名等字段,并在方法名字段上创建唯一索引,想要执行某个方法,就使用这个方法名向表中插入数据,成功插入则获取锁,执行完成后删除对应的行数据释放锁。
1,首先创建一个 分布式锁表
DROP TABLE IF EXISTS `distributed_lock`;
CREATE TABLE `distributed_lock` (
`distributed_lock_id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键',
`method_name` VARCHAR(64) NOT NULL COMMENT '加锁的方法名',
`distributed_lock_desc` VARCHAR(255) NOT NULL COMMENT '备注',
`inserted_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`distributed_lock_id`),
UNIQUE KEY `unique_key_method_name` (`method_name`) USING BTREE
) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='分布式锁';

2,将要执行的方法名作为参数,保存到分布式锁表中

INSERT INTO distributed_lock (distributed_lock_id,method_name, distributed_lock_desc) VALUES (816374617763712,'要加锁的方法名称', '描述信息');

如果可以插入成功,代表获得了锁,可以执行操作;逻辑执行完毕后,删除数据,释放锁

DELETE FROM distributed_lock WHERE method_name ='要释放锁的方法名称';

缺点:

1,需要考虑数据的性能以及保证数据库高可用 

2,不具备可重入的特性

3,如果宕机,会造成死锁

4,获取不到锁,直接返回失败,需要代码做循环获取锁

2,基于Redis实现(redis,redission,redLock,lua脚本,看门狗机制)
机制:jedis.set(String key, String value, String nx, String px, int time);
参数说明:
key:锁,保证唯一
value:竞争者的ID,例如线程名,释放锁的时候需要判断释放者是否未该锁的持有者
nx:SET IF NOT EXIST,即当key不存在时进行set操作;当key已存在则不做任何操作。
px:表示要给当前的锁设置一个过期时间,防止死锁
time:key的过期时间
执行set()方法只有两种结果:

  1.当key不存在(没有锁),进行加锁操作,并对锁设置一个过期时间,同时value为加锁的线程名。

  2.已经有锁存在,不做任何操作。

解锁:
  1. 判断当前解锁竞争者的线程名是否为锁的持有者,如果不是直接返回失败,如果是则进入第2步。
  2. 删除key,如果删除成功,返回解锁成功,否则解锁失败。
缺点:
1,死锁问题
2,不可重入
3,因为设置了过期时间,如果业务执行时间超过过期时间,会自动释放锁
4,需要保证redis的高可用
3,基于Zookeeper实现
机制:利用Zookeeper创建临时有序节点来实现分布式锁
  1. 当客户端来请求时,在锁空间下面创建一个临时有序节点。
  2. 如果当前节点的排序是这个空间下面最小的,则代表加锁成功,否则加锁失败,加锁失败后设置Watcher,等待前面节点的通知。
  3. 当前节点监听其前面一个节点,如果前面一个节点删除了就通知当前节点。
  4. 当解锁时当前节点通知其后继节点,并删除当前节点。
缺点:
需要保证zk的高可用





上一篇:20什么是distributed document store分布式文档存储


下一篇:12月工作汇报