分布式锁个人理解与主流方案

为什么分布式锁?
在分布式应用场景中在处理事务时我们常需要用到分布式锁。由于在分布式应用中应用在不同的主机中彼此独立,Jvm提供传统的原始锁无法对另一个主机上的应用干涉,导至每个应用持有一个把独立的锁,每个并发请求会出现同时持有数据的独立备份,没有办法保持原子性。于是为了保持事务的整体原子性和有序性,就有了分布式锁。

使用分布式锁之前:
在这里插入图片描述
使用分布式锁之后:
在这里插入图片描述

分布式锁主流方案:

1、redis
2、zookeeper

Redis分布式锁的主要实现方式

获取锁命令

SET resource_name my_random_value NX PX 30000

JAVA代码

try{
	lock = redisTemplate.opsForValue().setIfAbsent(lockKey, LOCK);
	logger.info("cancelCouponCode是否获取到锁:"+lock);
	if (lock) {
		// TODO
		redisTemplate.expire(lockKey,1, TimeUnit.MINUTES); //成功设置过期时间
		return res;
	}else {
		logger.info("cancelCouponCode没有获取到锁,不执行任务!");
	}
}finally{
	if(lock){	
		redisTemplate.delete(lockKey);
		logger.info("cancelCouponCode任务结束,释放锁!");		
	}else{
		logger.info("cancelCouponCode没有获取到锁,无需释放锁!");
	}
}

REDIS作为分布式锁的单点问题

使用的要点:

  • 同时设置值和过期时间:
    如果不用,先设置了值,再设置过期时间,这个不是原子性操作,有可能在设置过期时间之前宕机,会造成死锁(key永久存在。
    设置

  • value要具有唯一性
    这个是为了在解锁的时候,需要验证value是和加锁的一致才删除key。
    这是避免了一种情况:假设A获取了锁,过期时间30s,此时35s之后,锁已经自动释放了,A去释放锁,但是此时可能B获取了锁。A客户端就不能删除B的锁了。

  • redis可用性问题
    由于Redis作为分布式锁,而单机模式下的redis会出现可用性问题,当redis运行出现问题,就无法获取到锁。在高并发的场景下,这点十分致命。在主从模式下,即使有哨兵作主从切换,也会使redis出现一段时间的竞态状况,此时就会有可能出现锁丢失的问题。
    解决思路: 通过客户端的超时时间维护 判断 redis 是否失效,来避免锁丢失 。
    解决框架redisson

    redisson所有指令都通过lua脚本执行,redis支持lua脚本原子性执行
    redisson设置一个key的默认过期时间为30s,如果某个客户端持有一个锁超过了30s怎么办?
    redisson中有一个watchdog的概念,翻译过来就是看门狗,它会在你获取锁之后,每隔10秒帮你把 key的超时时间设为30s
    这样的话,就算一直持有锁也不会出现key过期了,其他线程获取到锁的问题了。
    redisson的“看门狗”逻辑保证了没有死锁发生。

ZOOKEEPER分布式锁的主要实现式

1 阻塞锁和非阻塞锁
根据业务特点,普通分布式锁有两种需求:阻塞锁和非阻塞锁。

阻塞锁:多个系统同时调用同一个资源,所有请求被排队处理。已经得到分布式锁的系统,进入运行状态完成业务操作;没有得到分布式锁的线程进入阻塞状态等待,当获得相应的信号并获得分布式锁后,进入运行状态完成业务操作。

非阻塞锁:多个系统同时调用同一个资源,当某一个系统最先获取到锁,进入运行状态完成业务操作;其他没有得到分布式锁的系统,就直接返回,不做任何业务逻辑,可以给用户提示进行其他操作。

利用 zookeeper 节点的不可重复性创建互斥节点。

实现流程
查看目标Node是否已经创建,已经创建,那么等待锁。
如果未创建,创建一个瞬时Node,表示已经占有锁。
如果创建失败,那么证明锁已经被其他线程占有了,那么同样等待锁。
当释放锁,或者当前Session超时的时候,节点被删除,唤醒之前等待锁的线程去争抢锁。

为了解决惊群问题:
我们将锁抽象成目录,多个线程在此目录下创建瞬时的顺序节点,因为Zk会为我们保证节点的顺序性,所以可以利用节点的顺序进行锁的判断。
首先创建顺序节点,然后获取当前目录下最小的节点,判断最小节点是不是当前节点,如果是那么获取锁成功,如果不是那么获取锁失败。
获取锁失败的节点获取当前节点上一个顺序节点,对此节点注册监听,当节点删除的时候通知当前节点。
当unlock的时候删除节点之后会通知下一个节点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值