分布式锁实现方法

分布式锁

目的

分布式锁的目的是达到数据的最终一致性;或者在分布式部署集群中,我们需要保证一个方法在同一时间内只能被一台机器上的一个线程执行

要求

1、这把锁要是一把可重入锁(避免死锁)
2、这把锁最好是一把阻塞锁
3、有高可用的获取锁和释放锁功能
4、获取锁和释放锁的性能要好

理论

分布式的CAP理论告诉我们“任何一个分布式系统都无法同时满足一致性(Consistency)可用性(Availability)分区容错性(Partition tolerance),最多只能同时满足两项。所以,很多系统在设计之初就要对这三者做出取舍。在互联网领域的绝大多数的场景中,都需要牺牲强一致性来换取系统的高可用性,系统往往只需要保证最终一致性,只要这个最终时间是在用户可以接受的范围内即可。

解决方案

  • 基于数据库实现分布式锁
  • 基于缓存(redis,memcached,tair)实现分布式锁

基于数据库实现分布式锁

1、创建一张锁表
在这里插入图片描述
2、当我们要锁住某个方法或资源时,我们就在该表中增加一条记录,因为我们对method_name做了唯一性约束,这里如果有多个请求同时提交到数据库的话,数据库会保证只有一个操作可以成功,那么我们就可以认为操作成功的那个线程获得了该方法的锁,可以执行方法体内容。

3、当我们想要释放锁的时候就删除这条记录。

问题及解决方案

1、这把锁强依赖数据库的可用性,数据库是一个单点,一旦数据库挂掉,会导致业务系统不可用。

数据库表搞成主备同步

2、这把锁没有失效时间,一旦解锁操作失败,就会导致锁记录一直在数据库中,其他线程无法再获得到锁。

新增定时任务,定时就数据库的超时数据删除一遍

3、这把锁只能是非阻塞的,因为数据的insert操作,一旦插入失败就会直接报错。没有获得锁的线程并不会进入排队队列,要想再次获得锁就要再次触发获得锁操作,性能较差。

// 每次重试直到成功
while(true) {
    retry insert until success
}

4、这把锁是非重入的,同一个线程在没有释放锁之前无法再次获得该锁。因为数据中数据已经存在了。

在数据库表中新增字段,记录当前获得锁的机器的主机信息和线程信息,那么下次再获取锁的时候先查询数据库,如果当前机器的主机信息和线程信息在数据库可以查到的话,直接把锁分配给他就可以了。

基于缓存_tair实现分布式锁

在这里插入图片描述
tair在put时,如果传入的 key 不存在,且传入指定的version,则tair在保存数据时,会将缓存的version设定为version+1;当 key 存在时,会判断version是不是和tair中的一致,一致才允许修改;如图中所示,第一次put时,传入 version 为2,则实际保存的version=3;下次再put时,如果 key 已存在,version则肯定和tair中的不一致;

所以当 put 成功时,则获取到锁;其他线程无法再获取

问题及解决方案

1、tair 可以集群部署,没有单点的问题
2、解锁失败问题:tair的put方法支持传入失效时间,到达时间之后数据会自动删除。但是设定多长是新的问题,过短可能当前线程还没执行完,过长可能其他线程等待时间加长
3、锁是非阻塞的,同样可通过 while true 循环获取锁,直到成功

// 每次重试直到成功
while(true) {
    retry tair.put until success
}

4、这把锁是非重入的,同一个线程在没有释放锁之前无法再次获得该锁。因为缓存中数据已经存在了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值