Redis 分布式锁实现 (三)

Redisson分布式锁一致性问题

对于主从结构的 redis 集群,如果在同步锁的过程中,主节点宕机,会将从节点中的某个节点选举为主节点,但是如果此时,锁没有同步成功,会导致分布式下锁并发异常

Redisson分布式锁

Redisson分布式锁

对此 Redisson 解决方案如下,通过多个单独的 redis 节点实现,必须所有的节点都获取锁成功,才算成功,就算在从节点未及时同步的情况下,由于并不能所有的节点都获取到锁,所以也是会锁获取失败,不会有分布式锁并发问题。

Redisson分布式锁

Redisson分布式锁

代码测试

这里使用三个 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 分布式锁的几种方案:

  1. 不可重入 Redis 分布式锁
    • 原理:利用setnx的互斥性;利用ex避免死锁;释放锁时判断线程标识
    • 缺陷:不可重入、无法重试、锁超时
  2. 可重入的 Redis 分布式锁:
    • 原理:利用 hash结构,记录线程标识和重入次数;利用 watchDog 延续锁时间;利用信号量控制锁重试等
    • 缺陷:redis 宕机引起锁失效问题
  3. Redisson 的 multiLock:
    • 原理:多个独立的 Redis 节点,必须在所有节点都获取重入锁,才算成功
    • 缺陷:运维成本高,实现复杂
本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
247
粉丝
18
喜欢
217
收藏
62
排名:731
访问:9753
私信
所有博文
社区赞助商