了解分布式锁,我们举个常见例子,一个抢券场景。
上面代码在单线程执行,或者多线程依次执行都没有问题。
但是如果两个线程并发,就有可能会出现问题。
如下图所示,假设库存只剩一个,两个线程都查出剩余优惠券但是两个线程还没有运行到扣减库存的那一步,这个时候两个线程都认为还有库存,都会执行扣减库存操作,就会出现问题。
这个时候我们只需要加个互斥锁就可以解决单体应用下的并发问题。
但是我们的程序有可能是分布式部署,这样每个服务器都可以拿到一把锁,我们上面的问题又会出现。
这个时候就需要用到分布式锁。
在应用程序外面设置一把锁,业务逻辑执行之前都去尝试获取这个锁,获取到锁才能执行业务逻辑,问题就可以解决啦。
Redis分布式锁
Redis实现分布式锁主要利用Redis的setnx命令。setnx是SET if not exists(如果不存在,则 SET)的简写。
获取锁:
释放锁:
Redis实现分布式锁如何合理的控制锁的有效时长?
1、根据业务执行时间预估
2、给锁续期
redisson实现的分布式锁-执行流程
redisson实现的分布式锁-可重入
可重入锁是指在同一个线程中,可以多次获得同一把锁而不会产生死锁的一种锁机制。
当一个线程持有了某个对象的锁时,在未释放该锁的情况下,可以再次获取这个锁,而不会被阻塞。这样可以确保同一线程对于同一把锁的多次加锁与解锁操作都能正常执行,从而避免了死锁的发生。
可重入锁的实现原理是,每个锁关联一个获取计数器和一个所有者线程,当计数器为0时表示该锁没有被任何线程持有,当某个线程获取了该锁时,计数器会变为1,并且记录下当前持有锁的线程,当同一个线程再次获取该锁时,计数器会递增,而在解锁时计数器递减,直到为0才表示该锁被完全释放。
使用可重入锁的好处是可以简化编程,使得编写并发代码更加方便,同时也降低了出现死锁的可能性。因此,在多线程编程中,可重入锁是一种非常重要且常用的锁机制。
redisson实现的分布式锁-主从一致性
通过使用 Redis 的 SETNX 命令(SET if Not eXists)可以实现简单的分布式锁。在这种方案中,当某个客户端尝试获取锁时,它会向 Redis 发送 SETNX 命令,如果返回值为 1,表示该客户端成功获取了锁;如果返回值为 0,表示锁已经被其他客户端持有,获取锁失败。
然而,仅仅使用 SETNX 命令实现的分布式锁可能存在一些主从一致性问题。因为 Redis 是一个主从复制的架构,主节点和从节点之间会存在一定的数据延迟。在某些情况下,如果主节点在获取锁成功后发生故障并且还没有来得及同步到从节点,此时从节点可能无法感知到主节点的状态变化,仍然认为锁处于被持有的状态,导致其他客户端误以为锁未被获取而重复获取锁。
为了解决这个主从一致性问题,可以引入一些额外的机制,比如使用 Redlock 算法、加入自旋重试机制、定时续约等方法来确保分布式锁的可靠性和一致性。这些方法能够在一定程度上降低因主从延迟带来的问题,提高分布式锁的稳定性和可靠性。
因此,在实际应用中,建议在使用 SETNX 命令实现分布式锁时,结合额外的机制来处理可能出现的主从一致性问题,以确保分布式锁的正确性和可靠性。
RedLock(红锁):不能只在一个redis实例上创建锁,应该是在多个redis实例上创建锁(n / 2 + 1),避免在一个redis实例上加锁。