众所周知,在微服务架构中,往往都会有集群的. 那么并发肯定是少不了的.
单系统我们使用Synchronized
Lock
Semaphore
去轻而易举的解决掉.
接下来思考一个问题. 为什么不用Spring自带的RedisTemplate或RedisLockRegistry(基于Lock实现的一个分布式锁)呢?
redisTemplate.opsForValue().setIfAbsent();
// 或者
spring-integration-redis的 redisLockRegistry.obtain("key");
补充:
RedisLockRegistry是spring-integration-redis中提供redis分布式锁实现类.主要是通过redis锁+本地锁双重锁的方式实现的一个比较好的锁.
当你在真是项目中使用后你可能会发现这几个问题.
- 你的业务代码执行时间会超过你的锁时间.
- 你刚拿到锁后还没设置过期时间,这时候redis宕机了.
- 反正就是各种恶心你的问题.
- (补充:RedisLockRegistry底层也是基于lua脚本是实现的,唯一的不足就是没有锁超时的检测延迟机制. 类似redisson的看门狗. 需要自己去实现.)
用了redisson就什么都可以解决了.
Redission通过Netty Future机制,Semaphore (jdk信号量),redis锁实现.
Redisson通过Netty的TimerTask、Timeout 工具完成锁的定期刷新任务.
它也是可重入锁.
代码so easy.
pom
<!-- https://mvnrepository.com/artifact/org.redisson/redisson-spring-boot-starter -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.12.5</version>
</dependency>
配置文件
spring.redis.database=1
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=
java
package com.example.yiran.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
/**
* @description:
* @author: wajn
* @create: 2020-07-12 00:32
**/
@Configuration
public class RedissonClientConfig {
@Bean
public RedissonClient redisson(final RedisProperties redisProperties) throws IOException {
System.out.println(111);
Config config = new Config();
config.useSingleServer()
.setAddress(String.format("redis://%s:%s", redisProperties.getHost(), redisProperties.getPort()))
.setDatabase(redisProperties.getDatabase())
;
return Redisson.create(config);
}
}
@GetMapping("clear")
public void clear() throws InterruptedException {
RLock lock = redissonClient.getLock("locl-test");
if (lock.tryLock()) {
System.out.println("11111");
Thread.sleep(3000000L);
//看门狗会默认查询锁是否过期. 如果快过期了会不断延时过期时间.
System.out.println("执行完毕业务");
lock.unlock();
} else {
System.out.println("222222");
}
}
高阶玩法:
#Redisson配置
singleServerConfig:
address: "redis://127.0.0.1:6379"
password: null
clientName: null
database: 1 #选择使用哪个数据库0~15
idleConnectionTimeout: 10000
pingTimeout: 1000
connectTimeout: 10000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
reconnectionTimeout: 3000
failedAttempts: 3
subscriptionsPerConnection: 5
subscriptionConnectionMinimumIdleSize: 1
subscriptionConnectionPoolSize: 50
connectionMinimumIdleSize: 32
connectionPoolSize: 64
dnsMonitoringInterval: 5000
#dnsMonitoring: false
threads: 0
nettyThreads: 0
codec:
class: "org.redisson.codec.JsonJacksonCodec"
transportMode: "NIO"
package com.example.yiran.config;
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;
import java.io.IOException;
/**
* @description:
* @author: wajn
* @create: 2020-07-12 00:32
**/
@Configuration
public class RedissonClientConfig {
@Bean
public RedissonClient redisson() throws IOException {
System.out.println(111);
// 本例子使用的是yaml格式的配置文件,读取使用Config.fromYAML,如果是Json文件,则使用Config.fromJSON
Config config = Config.fromYAML(this.getClass().getClassLoader().getResource("redisson-config.yml"));
return Redisson.create(config);
}
}