七、分布式锁
1、说明
我们在开发应用的时候,为了保证一个方法或属性在高并发情况下的同一时间只能被同一个线程执行,可以使用并发处理相关的功能进行互斥控制。但随着业务的发展,一个应用部署到几台机器上然后做负载均衡,这时,原单机部署情况下的并发控制锁策略失效,单纯的应用并不能提供分布式锁的能力。因此就要使用分布式锁来保证一个方法或属性在高并发情况下的同一时间只能被同一个线程执行。
2、分布式锁的特点
- 在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行
- 高可用的获取锁和释放锁
- 高性能的获取锁和释放锁
- 具备可重入特性(指线程在持有锁的情况下再次请求加锁,一个锁支持同一个线程的多次加锁)
- 锁具备失效特性,防止死锁
- 具备非阻塞锁特性,没有获取到锁的时候直接返回获取锁失败
这里介绍的分布式锁是基于redis实现的。
3、实现基本概念
3.1 加锁
redis的加锁方式非常简单,使用
SETEX key seconds value
命令即可完成加锁的条件。说明:
(1)当且仅当key不存在时,设置key才会返回1,若存在,则会返回0;这样可以保证同一时间只能被一个线程获取到,同时也可以直接返回获取锁失败;
(2)添加了过期时间second;保证key可以超时失效,防止死锁;
(3)redis的高性能,可以保证锁的高可用和高性能
(4)value可以设置为一个随机数,释放锁时先判断随机数释放一致,然后再删除key,这样可以确保当前线程占有的锁不会被其他线程释放。
3.2 解锁
当得到锁的线程执行完成后,需要释放锁,以便其他线程可以进入。使用
del key
命令删除redis中的key,这样其他线程在下一次的加锁时,就因为找不到而重新获得到锁。
4、Redis锁的问题
redis锁虽然使用简单方便,但也存在几个问题:
4.1 超时问题
Redis的分布式锁不能解决超时问题!当我们使用redis进行加锁的时候,会有一个过期时间second防止死锁的发生,但如果此时业务逻辑执行的时间太长,以至于到达了设置的过期时间时,业务还在执行。第一个线程的锁被释放,第二个线程就提前持有了这把锁,导致临界区的代码不能严格串行执行。
4.2 集群问题
在Redis集群中,当主节点挂掉时,从节点会取而代之。现在有这样一种情况:
- 第一个客户端在主节点成功申请了一把锁;
- 这个锁数据还没有来得及同步到从节点时,主节点挂掉了,然后从节点变成了主节点;
- 当另外一个客户端请求加锁时,由于新的主节点内部没有这个锁,所以加锁成功;
- 这样系统中同样的一把锁就会被两个客户端同时持有
这种情况只有在主从同步失败时才会产生,而且持续时间极短,因此大部分情况下可以忽略,因此这里只做说明。
如果为了解决这个问题,可以看看Redlock算法。

浙公网安备 33010602011771号