1.分布式锁简介
锁机制是一种用于控制多个线程对共享资源进行访问的技术。锁允许只有一个线程访问共享资源,其他线程在锁被释放之前需要等待。锁的使用可以防止多个线程同时访问共享资源,从而保证了线程安全。JVM 中提供了大量内置锁用于解决并发安全问题,例如 Synchronized、ReentrantLock、ReadWriteLock、StampedLock、LockSupport。
1.1 分布式锁的定义
相较于 JVM 内置锁分布式锁是在分布式系统中用于控制多个节点对共享资源进行访问的一种机制。在分布式环境中,多个节点同时访问共享资源可能会导致数据不一致性、竞态条件和并发问题。分布式锁的目的是确保在任何时刻只有一个节点可以获取锁,并且可以安全地访问共享资源,从而维护数据的一致性和正确性。分布式锁常见的应用场景如下:
- 缓存同步:在分布式缓存中,多个节点可能同时请求某个缓存项,为了避免缓存击穿或热点数据并发访问的问题,可以使用分布式锁来控制只有一个节点可以从数据库中加载数据到缓存,其他节点需要等待。
- 任务调度:在分布式任务调度系统中,多个节点可能同时竞争执行同一个任务,为了避免重复执行,可以使用分布式锁来确保只有一个节点执行任务,其他节点需要等待。
- 分布式限流:分布式限流需要对请求进行计数,当请求数量达到一定阈值时,需要限制后续的请求。使用分布式锁可以确保多个节点对请求数量的计数是准确的,避免并发计数导致不一致的情况。
- 分布式事务:在分布式事务中,可能需要对多个资源进行操作,需要保证多个资源的一致性。使用分布式锁可以防止多个节点同时操作同一个资源,确保事务的正确执行。
- 全局唯一性约束:在分布式系统中需要保证某些操作的全局唯一性,比如订单号、流水号等。使用分布式锁可以确保生成的唯一标识不会重复。
- 并发控制:一些分布式场景中,可能需要对某些操作进行并发控制,以避免竞态条件和数据不一致。使用分布式锁可以控制多个节点的并发操作。例如秒杀、抢票等场景出现库存并发安全问题。
1.2 分布式锁的实现方案
实现分布式锁的方案有多种,常见方式如下:
- 基于数据库的分布式锁。可以利用数据库的事务和唯一性约束来实现分布式锁。在数据库中创建一个特殊的锁表,节点在获取锁时往表中插入一条记录,释放锁时删除这条记录。由于数据库的事务特性,可以确保只有一个节点能够成功插入记录,从而实现锁的效果。但是这种方法可能会对数据库性能产生一定影响,一般不推荐使用。
- 基于缓存的分布式锁。利用分布式缓存(如 Redis)来实现锁。节点在获取锁时在缓存中设置一个带有过期时间的键值对,释放锁时删除该键值对。由于缓存是内存存储,相对数据库来说更快速,适用于对性能有严格要求的分布式应用场景,但需要考虑缓存的高可用性和失效时间问题。
- 基于 ZooKeeper 的分布式锁。ZooKeeper 是一个分布式协调服务,可以用来实现分布式锁。节点在获取锁时在 ZooKeeper 中创建一个临时有序节点,释放锁时删除这个节点。通过 ZooKeeper 的临时节点和有序性特性,可以实现分布式锁。这种方法具有较高的可靠性和一致性,适用于需要高可用性、严格一致性和协调机制的分布式应用场景。
- 基于分布式数据库的分布式锁:一些分布式数据库提供了分布式事务和行级锁支持,可以用来实现分布式锁。类似于基于数据库的方法,但在分布式数据库中更容易水平扩展和维护。
- 基于乐观锁和 CAS(比较并交换)的分布式锁:这种方法使用乐观锁的思想,节点在获取锁时会尝试更新共享资源的版本号或标记,如果更新成功则表示获得了锁。这通常依赖于底层平台提供的原子操作(如 CAS 操作),是一种高效的分布式锁实现方式。
由于 Redis 的超高性能和低延迟,ZooKeeper 的强一致性和高可用性,使得 Redis 和 Zookeeper 成为主流的分布式锁实现方案之一。
1.3 实现分布式锁的注意事项
实现分布式锁需要满足以下特性:
- 互斥:同一时刻保证只有一个线程获取到锁,其他线程阻塞等待获取锁。
- 锁应设置超时时间:在分布式环境下,由于 Redis 故障或网络 IO 等原因导致锁持有方无法及时释放锁资源,其他节点则会长时间排队阻塞等待获取锁资源,可能出现死锁现象,严重影响程序执行效率。为了防止释放锁失败,通常会设置锁的超时时间,一旦锁长时间未被释放,则锁自动过期,释放锁后其他线程竞争锁。
- 锁的可重入性:锁的重入性是指同一个线程是否可以多次获取同一把锁而不被阻塞
- 锁的续期:如果已经设置了锁的过期时间,当到锁过期但是业务逻辑还未执行完成,此时无法保证业务正常执行,在这种情况应需要支持锁的自动续期。
2.基于 Redis 实现分布式锁
2.1 基于 setnx 命令实现分布式锁
2.2 基于 lua 脚本实现分布式锁
2.3 基于 Redlock 算法实现分布式锁
Redlock 是 Redis 官方提供的一种分布式锁算法,使用多个 Redis 节点实现高可用性的分布式锁。但需要注意,Redlock 算法对于网络延迟和节点故障有一定的容忍度,适用于一些高可用性的场景。
2.4 基于 Redisson 实现分布式锁
Redisson 是一个强大的 Redis 库,内置了分布式锁的实现,封装了 Redis 原生命令,提供了更高级的特性如可重入锁、公平锁等。
Java知识库