Redis 分布式锁实现 (三)
Redisson 分布式锁一致性问题#
对于主从结构的 redis 集群,如果在同步锁的过程中,主节点宕机,会将从节点中的某个节点选举为主节点,但是如果此时,锁没有同步成功,会导致分布式下锁并发异常
对此 Redisson 解决方案如下,通过多个单独的 redis 节点实现,必须所有的节点都获取锁成功,才算成功,就算在从节点未及时同步的情况下,由于并不能所有的节点都获取到锁,所以也是会锁获取失败,不会有分布式锁并发问题。
代码测试#
这里使用三个 redis node 进行测试
配置类#
@Configuration
public class RedissonConfig {
@Bean
public RedissonClient redissonClient() {
// 配置类
Config config = new Config();
// 添加 redis 地址,这里添加了单点地址,也可以使用 config.useClusterServers() 添加集群地址
config.useSingleServer().setAddress("redis://127.0.0.1:6379").setPassword("root123");
// 创建客户端
return Redisson.create(config);
}
@Bean
public RedissonClient redissonClient2() {
// 配置类
Config config = new Config();
// 添加 redis 地址,这里添加了单点地址,也可以使用 config.useClusterServers() 添加集群地址
config.useSingleServer().setAddress("redis://127.0.0.1:6380").setPassword("root123");
// 创建客户端
return Redisson.create(config);
}
@Bean
public RedissonClient redissonClient3() {
// 配置类
Config config = new Config();
// 添加 redis 地址,这里添加了单点地址,也可以使用 config.useClusterServers() 添加集群地址
config.useSingleServer().setAddress("redis://127.0.0.1:6381").setPassword("root123");
// 创建客户端
return Redisson.create(config);
}
}
测试代码#
@SpringBootTest
public class RedisTest {
@Resource
private RedisTemplate<String, Object> redisTemplate;
// private StringRedisTemplate redisTemplate;
@Test
void test1() {
redisTemplate.opsForValue().set("name", "HuDu");
System.out.println(redisTemplate.opsForValue().get("name"));
}
@Test
void test2() {
Student student = new Student(1, "HuDu", 18);
redisTemplate.opsForValue().set("student", student);
System.out.println(redisTemplate.opsForValue().get("student"));
}
@Test
void test3() {
redisTemplate.opsForHash().put("user","name","hudu");
redisTemplate.opsForHash().put("user","age","21");
Map<Object, Object> user = redisTemplate.opsForHash().entries("user");
System.out.println(user);
}
@Test
void test4() {
List<Student> students = new ArrayList<>();
for (int i = 1; i <= 6; i++) {
Student student = new Student(i, "name" + i, 18 + i);
students.add(student);
}
redisTemplate.opsForList().leftPushAll("studentList",students);
List<Object> studentList = redisTemplate.opsForList().range("studentList", 0, -1);
assert studentList != null;
studentList.forEach(System.out::println);
}
}
总结#
Redis 分布式锁的几种方案:
- 不可重入 Redis 分布式锁
- 原理:利用
setnx
的互斥性;利用ex
避免死锁;释放锁时判断线程标识 - 缺陷:不可重入、无法重试、锁超时
- 原理:利用
- 可重入的 Redis 分布式锁:
- 原理:利用 hash 结构,记录线程标识和重入次数;利用 watchDog 延续锁时间;利用信号量控制锁重试等
- 缺陷:redis 宕机引起锁失效问题
- Redisson 的 multiLock:
- 原理:多个独立的 Redis 节点,必须在所有节点都获取重入锁,才算成功
- 缺陷:运维成本高,实现复杂
本作品采用《CC 协议》,转载必须注明作者和本文链接