分布式锁(Distributed Lock)是一种用于分布式系统中的同步机制,主要是为了防止分布式系统中,多个服务实例同时操作一个共享资源所带来的并发安全问题。
分布式锁的实现方案有多种,例如以下这几种:
综合以上方案来看,基于数据库实现的分布式锁不适用于高并发场景,而基于 Zookeeper 实现的分布式锁又需要额外部署 Zookeeper 服务,增加了运营成本,所以使用 Redis 实现分布式锁是目前主流的实现方案。
2.为什么Redis可以实现分布式锁?
因为Redis 作为一个独立的第三方系统(数据中间件),其本身就支持分布式应用。也就是针对于 Redis 的所有操作,所有的分布式系统都是全局可见的,如下图所示:
使用 Redis 实现分布式锁的方案有以下 4 种:
问题解释
综合以上实现方案来看,生产级别使用 Redis 实现分布式锁的方案,应该选用 Redisson 框架。
Redisson 是一个开源的用于操作 Redis 的 Java 框架。与 Jedis 和 Lettuce 等轻量级的 Redis 框架不同,它提供了更高级且功能丰富的 Redis 客户端。它提供了许多简化 Redis 操作的高级 API,并支持分布式对象、分布式锁、分布式集合等特性。
添加 Redisson 依赖:
<dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId></dependency>
将 RedissonClient 对象保存到 Spring Ioc 容器,并为其设置 Redis 服务连接信息,具体实现代码如下:
import org.redisson.Redisson;import org.redisson.api.RedissonClient;import org.redisson.config.Config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class RedissonConfig {@Beanpublic RedissonClient redissonClient() {Config config = new Config();// 也可以将 redis 配置信息保存到配置文件config.useSingleServer().setAddress("redis://127.0.0.1:6379");return Redisson.create(config);}}
Redisson 分布式锁的操作和 Java 中的 ReentrantLock(可重入锁)的操作很像,都是先使用 tryLock 尝试获取(非公平)锁,再通过 unlock 释放锁,具体实现如下:
import org.redisson.api.RLock;import org.redisson.api.RedissonClient;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import java.util.concurrent.TimeUnit;@RestControllerpublic class LockController {@Autowiredprivate RedissonClient redissonClient;@GetMapping("/lock")public String lockResource() throws InterruptedException {String lockKey = "myLock";// 获取 RLock 对象RLock lock = redissonClient.getLock(lockKey);try {// 尝试获取锁(尝试加锁)(锁超时时间是 30 秒)boolean isLocked = lock.tryLock(30, TimeUnit.SECONDS);if (isLocked) {// 成功获取到锁try {// 模拟业务处理TimeUnit.SECONDS.sleep(5);return "成功获取锁,并执行业务代码";} catch (InterruptedException e) {e.printStackTrace();} finally {// 释放锁lock.unlock();}} else {// 获取锁失败return "获取锁失败";}} catch (InterruptedException e) {e.printStackTrace();}return "获取锁成功";}}
Redisson 默认创建的分布式锁是非公平锁(出于性能的考虑),想要把它变成公平锁可使用以下代码实现:
RLock lock = redissonClient.getFairLock(lockKey);// 获取公平锁
Redisson 还可以创建读写锁,如下代码所示:
RReadWriteLock lock = redissonClient.getReadWriteLock(lockKey); // 获取读写锁lock.readLock();// 读锁lock.writeLock(); // 写锁
读写锁的特点就是并发性能高,它是允许多个线程同时获取读锁进行读操作的,也就是说在没有写锁的情况下,读取操作可以并发执行,提高了系统的并行度。但写锁则是独占式的,同一时间只有一个线程可以获得写锁,无论是读还是写都无法与写锁并存,这样就确保了数据修改时的数据一致性。
Redisson 也支持联锁,也叫分布式多锁 MultiLock,它允许客户端一次性获取多个独立资源(RLock)上的锁,这些资源可能是不同的键或同一键的不同锁。当所有指定的锁都被成功获取后,才会认为整个操作成功锁定。这样能够确保在分布式环境下进行跨资源的并发控制。
联锁的实现示例如下:
// 获取需要加锁的资源RLock lock1 = redisson.getLock("lock1");RLock lock2 = redisson.getLock("lock2");// 联锁RedissonMultiLock multiLock = new RedissonMultiLock(lock1, lock2);try {// 一次性尝试获取所有锁if (multiLock.tryLock()) {// 获取锁成功...}} finally {// 释放所有锁multiLock.unlock();}
本网站的文章部分内容可能来源于网络和网友发布,仅供大家学习与参考,如有侵权,请联系站长进行删除处理,不代表本网站立场,转载者并注明出处:https://jmbhsh.com/qitabaihuo/34402.html