分布式锁-Redisson实现

目录

本地锁的局限性

Redisson解决分布式锁问题


在分布式环境下,分布式锁可以保证在多个节点上的并发操作时数据的一致性和互斥性。分布式锁有多种实现方案,最常用的两种方案是:zookeeper和redis,本文介绍redis实现分布式锁方案。

本地锁的局限性

JDK中自带的synchronized及lock锁,这些锁都是本地锁,在一个节点服务(一个JVM)下可以实现"锁"的效果,一旦服务多实例,本地锁就会存在问题。下方示例演示并发对redis的值做自增操作,观察效果,步骤如下:

1、编写请求和服务接口

此代码的主要逻辑是redis中key=num的值每次+1(初始值是0),其中redisTest方法上加上本地锁(synchronized)

java 复制代码
@GetMapping("/redisTest")
public GenericWebResult redisTest() {
	Long result = this.blogContentService.redisTest();
	log.info("设置redis中num值:{}",result);
	return GenericWebResult.ok((Object) "测试成功",result);
}
java 复制代码
@Override
public synchronized Long redisTest() throws BusinessException {
	Long result = 0l;
	String key = "num";
	RBucket<Object> bucket = this.redissonClient.getBucket(key);
	if(bucket != null) {
		Long ori = (Long)bucket.get();
		result = ori.longValue() + 1;
		this.redissonClient.getBucket(key).set(result);
	}
	return result;
}

2、单个实例启动后,用jemter并发请求测试

单实例启动后,服务端口:8888,jemter通过100个线程并发请求访问后,redis中key=num的值是100,符合预期。

3、后台服务启动多个实例, 再次用jemter并发请求测试

后台服务启动了2个实例,端口分别是8888和9999,并通过网关gateway对外公布统一的请求地址,网关会自动均衡到端口是8888和9999的2个服务中(这部分的配置不在此文赘述,详情见网关Gateway-CSDN博客),网关服务的端口是7777,请求的统一地址是:http://localhost:7777/blog-content/blogContent/redisTest ,通过jmeter测试如下(num初始恢复到0):

执行后,发现redis中key=num的值变成了65,不是100,不符合预期,证明本地锁在分布式环境下是有局限性的,它只能保证在一个JVM下锁的有效性。

Redisson解决分布式锁问题

Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务,其中就包含了各种分布式锁的实现。使用Redisson实现分布式锁,需要如下步骤:

1、项目添加依赖

XML 复制代码
<!-- redisson -->
<dependency>
	<groupId>org.redisson</groupId>
	<artifactId>redisson-spring-boot-starter</artifactId>
	<exclusions>
		<exclusion>
			<groupId>org.redisson</groupId>
			<artifactId>redisson-spring-data-23</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>org.redisson</groupId>
	<artifactId>redisson-spring-data-26</artifactId>
	<version>3.47.0</version>
</dependency>

2、改造redisTest方法,引入锁

通过redissonClient.getLock获取锁,在执行业务逻辑前锁住lock.lock(),执行完业务逻辑后释放锁lock.unlock()

java 复制代码
@Override
public Long redisTest() throws BusinessException {

	Long result = 0l;
	RLock lock = redissonClient.getLock("lock");
	lock.lock();
	//业务逻辑
	try {
		log.info("业务逻辑开始...");
		Thread.sleep(1000);//模拟业务逻辑时长
		String key = "num";
		RBucket<Object> bucket = this.redissonClient.getBucket(key);
		if(bucket != null) {
			Long ori = (Long)bucket.get();
			result = ori.longValue() + 1;
			this.redissonClient.getBucket(key).set(result);
		}
		log.info("业务逻辑结束...");
	} catch (InterruptedException e) {
		e.printStackTrace();
	} finally {
		lock.unlock();
		log.info("redis 解锁...");
	}
	return result;
}

3、和第一章节一样,后台服务同样启动2个实例,端口分别是8888和9999,用jmeter模拟并发请求网关端口。

从后台请求日志可以看出,2个服务每隔1秒获取到锁,然后执行业务逻辑(num++),最终num的值是100,符合预期,实现了分布式环境下锁的效果。

相关推荐
快乐肚皮8 天前
Redisson学习专栏(二):核心功能深入学习(分布式锁,分布式集合,原子操作与计数器,事件与监听)
java·分布式·分布式锁·redisson·事件·分布式集合·原子
Uranus^11 天前
深入解析Spring Boot与Redis的集成实践
spring boot·redis·缓存·分布式锁
杨不易呀1 个月前
Java面试高阶篇:Spring Boot+Quarkus+Redis高并发架构设计与性能优化实战
spring boot·redis·高并发·分布式锁·java面试·quarkus
懒虫虫~1 个月前
利用Redisson分布式锁解决多服务器数据刷新问题
springboot·分布式锁·redisson
忘忧人生2 个月前
Redisson 实现分布式锁
分布式锁·redisson·
morris1312 个月前
【redis】redis实现分布式锁
数据库·redis·缓存·分布式锁
Amd7942 个月前
FastAPI中Pydantic异步分布式唯一性校验
redis·fastapi·分布式锁·多级缓存·pydantic·唯一性校验·异步校验
小小工匠2 个月前
Redisson - 分布式锁和同步器
分布式锁·redisson·同步器