一、分布式锁介绍
分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式环境下,如果不同系统或同一个系统的不同主机之间共享某一资源,在访问这一资源的时候需要互斥来防止彼此干扰保证一致性,此时就需要分布式锁来控制共享资源的访问。
分布式锁的原则:
- 互斥性:同一时刻只有一个服务实例能获取到锁,从而访问共享资源。
- 高可用:分布式锁的实现应具有高可用性,即使部分服务实例或节点故障,也不会影响锁的获取和释放。
- 可重入性:同一个服务实例可以多次获取同一把锁,以防止服务实例在持有锁期间因为自身调用导致死锁。
- 锁超时:如果持有锁的服务实例因故障未能释放锁,锁应能在一段时间后自动释放,以避免死锁。
在传统单体多线程环境下,我们可以用线程资源锁来实现对资源的互斥访问,如JDK中提供的ReentrantLcok和Synchronized。但在分布式系统中,多线程应用会分布在不同机器中,传统的锁机制将无法保证数据的一致性,需要分布式锁来支持。
二、主流分布式锁实现方式及比较
目前分布式锁并没有统一的实现方案,基于行业内各公司的实践,主要有以下三种实现方式:
- 基于数据库:
- 利用数据库的唯一索引或表锁来实现。但这种方式性能较差,且容易成为系统的瓶颈。
- 基于Redis:
- 使用Redis的
SETNX
(Set if Not eXists)命令或SET
命令结合过期时间(EX
参数)来实现。 - 另一种常见的做法是使用Lua脚本来保证操作的原子性,即检查锁是否存在并设置锁。
- Redis分布式锁的一个问题是,如果Redis服务器宕机,可能会导致锁永久丢失。可以通过Redis集群来提高可用性。
- 使用Redis的
- 基于Zookeeper:
- Zookeeper通过创建临时顺序节点来实现分布式锁。所有客户端在同一父节点下创建临时顺序节点,通过节点序号的大小来确定锁的持有者。
- Zookeeper具有较好的容错性和可靠性,但其性能相比Redis可能稍逊一筹。
- 基于Chubby或etcd:
- 这些是专门为分布式系统设计的协调服务,提供了强大的分布式锁功能。
- 它们通过选举机制来确保服务的高可用性。
下面将分别对以上三种分布式锁做 简要的介绍。
2.1基于数据库的分布式锁
用数据库实现分布式锁利用数据库表的唯一键:同一时刻,多客户端线程同时向一个表中插入同样的记录,在唯一键的约束下,只有一个线程插入成功,流程图如下: