04-redis-分布式锁-edisson
1 基本概念
百度百科:控制分布式系统之间同步访问共享资源方式。
在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,这个时候,便需要使用到分布式锁。
在单机环境中可以使用Lock、Synchronized可以处理多线程并发问题可以确保同一时刻只有一个线程能够访问或修改共享资源。但是在分布式系统中,各个节点不在一个jvm环境中,进而需要新的技术方案来保证不同节点的一个互斥性。一般可以使用MySQL、Zookeeper、redis等方案,本文介绍redis中redisson的方式。
2 基本要求
1、互斥性:在任何时刻,只能有一个客户端持有锁、防止多个客户端同时访问共享资源
2、安全性:锁只能由持有它的客户端释放,其他客户端无法删除或释放该锁
3、可重入:持有锁的客户端可以重复进入
4、避免死锁:即使持有锁的客户端发生故障(比如宕机),锁也能通过超时或者释放机制被释放,
避免系统永久阻塞
5、容错性:在部分节点故障时,锁服务仍能正常运行,客户端可以正常获取和释放锁
扩展特性:
高性能:获取和释放锁的操作应高效,避免成为系统瓶颈。
可重入性:允许同一客户端多次获取同一把锁,避免自我阻塞。
非阻塞性:如果获取锁失败,客户端应能立即返回结果,而非长时间等待
3 redisson分布式锁
3.1 代码实现
3.1.1 导入jar包
<!-- Redis Starter --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- Redisson Starter (推荐) --><dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.23.4</version> <!-- 使用最新版本 --></dependency>
3.1.2 配置
application.yml配置
spring:redis:host: localhostport: 6381password: 123456 # 若无密码可删除database: 0
配置类
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Component
@ConfigurationProperties(prefix = "spring.redis")
public class RedisConfigData {private String host;private Integer port;private String password;private Integer database;public String getHost() {return host;}public void setHost(String host) {this.host = host;}public Integer getPort() {return port;}public void setPort(Integer port) {this.port = port;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Integer getDatabase() {return database;}public void setDatabase(Integer database) {this.database = database;}
}
package com.hyq.config;import com.hyq.prefix.RedisConfigData;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RedissonConfig {@Autowiredprivate RedisConfigData redisConfigData;@Beanpublic RedissonClient redissonClient() {Config config = new Config();// 单节点模式(根据spring.redis.*自动注入配置)config.useSingleServer()// 设置服务器的ip和端口号.setAddress("redis://" + redisConfigData.getHost() + ":" + redisConfigData.getPort())// 密码.setPassword(redisConfigData.getPassword()).setDatabase(redisConfigData.getDatabase());return Redisson.create(config);}}
使用RedissonClient获取分布式锁,后面通过这个入口查看源码
// 分布式锁名称:myLock
RLock lock = redissonClient.getLock("myLock");
// 尝试获取分布式锁 参数:等待时间 释放时间 时间单位
if(lock.tryLock(10, -1, TimeUnit.SECONDS)) {System.out.println("获取锁成功,");Thread.sleep(10000);// 释放锁lock.unlock();
} else {System.out.println("获取锁失败, 已经有人在支付cls");
}
3.2 底层逻辑图
在redisson中分布式锁满足互斥、可重入、安全、容错等特性。
底层采用的是Hash存储结构:key:分布式锁名称 field: uuid+线程ID value:重入次数
存储线程ID主要是为了解决可重入,判断当前是否是获取锁的线程