分布式锁以及分布式锁在项目中的使用总结

1 分布式锁的三种实现方式

第一:基于数据库
第二:基于缓存
第三:基于Zookeeper

2 基于数据库实现分布式锁

要实现分布式锁,最简单的方式可能就是直接创建一张锁表,然后通过操作该表中的数据来实现了。
当我们要锁住某个方法或资源时,我们就在该表中增加一条记录,想要释放锁的时候就删除这条记录。

CREATE TABLE `methodLock` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `method_name` varchar(64) NOT NULL DEFAULT '' COMMENT '锁定的方法名',
  `desc` varchar(1024) NOT NULL DEFAULT '备注信息',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '保存数据时间,自动生成',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uidx_method_name` (`method_name `) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='锁定中的方法';

当我们想要锁住某个方法时,执行以下SQL:

insert into methodLock(method_name,desc) values (‘method_name’,‘desc’);

方法执行完成后,释放锁:

delete from methodLock where method_name ='method_name'

上述方法看起来原理很简单,但是会存在一些问题?

  1. 这把锁没有失效是时间,一旦解锁失败,就会导致锁一直在数据库里边,导致业务系统不可用。
  2. 这把锁是非阻塞的,不管成功还是失败都是立即返回。这把锁是非阻塞的,不管成功还是失败都是立即返回的。
  3. 这个锁是非重入的。

要解决上述问题,其实也简单,可通过下边的操作来避免上述问题。
这把锁没有失效是时间?有两个方案:

  1. 使用Spring的嵌套事务来操作。使用分布式锁的时候就起事务,业务代码再起一个事务,使用的传播行为是required new,可以在上层事务回滚后不影响内层事务;
  2. 一个定时任务,每隔一定时间把数据库中的超时数据清理一遍。

非阻塞的

  1. 搞一个while循环,不断的往数据库里边插入数据,直到插入成功为止或者到期为止。

这个锁是非重入的
在数据行记录中,记录下线程的信息,当获取锁的时候,先判断线程是否是当前线程,是的话,返回成功,不是的话,返回失败。

3 基于缓存

相对于基于数据库实现分布式锁的方案来说,基于缓存的实现在性能上能有很大的优势;
目前成熟的缓存数据库有很多,redis、memcached以及阿里能内中缓存中间件tair等
实现的原理是加锁时,利用往缓存里边写入一条数据,其中某一个字段是唯一的。
锁释放时手动删除这个记录。
这个方案也存在一些问题:

  1. 这把锁是非重入锁
  2. 这把锁是非阻塞的。

非重入锁?
和数据库实现分布式锁类似,其实问题还是一个问题,解决方案也是类似的。
在存储的数据记录中查询线程信息,如果和当前线程是一致的就直接获取锁,不一致就获取锁失败。
非阻塞的
同样的加一个循环,直到加锁成为未知。

3 基于zookeeper

可以基于zk的临时节点做分布式锁。
大致思想就是客户端在对某个方法加锁时,都会在相应的方法节点下加一个临时有序节点,在客户端执行完业务,会释放链接,临时节点自然删除。判断是否获取锁的逻辑是判断当前临时节点序号是否是做小的,如果是则获取到了锁。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值