Redisson

本文探讨了Redisson在实现分布式锁中的关键原理,包括可重入锁的机制、Lua脚本的应用、超时释放和解决主从一致性问题的方法。通过实例讲解,读者将掌握如何利用Redisson在秒杀优惠券场景中避免竞态条件和主从切换带来的问题。

目录

Redisson

Redisson入门

Redisson可重入锁原理(解决不可重入)

Lua实现获取锁​编辑

Lua脚本实现释放锁​编辑

Redisson的深入理解(解决不可重试和超时释放)

总结

解决主从一致性问题

总结​


前文链接:

主要是要学习redis分布锁的原理,其实redis有专门用来处理这些问题的工具

(1条消息) Redis——实现优惠券秒杀_486过于烦躁的博客-优快云博客

(1条消息) 基于Redis的分布式锁实现(秒杀优惠券的优化)_486过于烦躁的博客-优快云博客

Redisson可以解决以下四个问题 

Redisson

之所以引用Redisson是因为前文我们自己实现的锁不满足可重入性(什么是 “可重入”:可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁)


Redisson入门

 

实现

    @Resource
    private RedissonClient redissonClient;


     @Transactional
    public Result createVoucherOrder(Long voucherId) {
        //获取用户Id
        UserDTO user = UserHolder.getUser();
        Long userId = user.getId();

        //创建锁对象
        RLock redisLock = redissonClient.getLock("lock:order:" + userId);

        //尝试获取锁
        boolean isLock = redisLock.tryLock();
        //判断
        if(!isLock){
            //获取锁失败,直接返回失败或者重试
            return Result.fail("不允许重复下单");
        }

        try {
            //一人一单
            Integer count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();
            if(count>0){
                //说明用户之前买过了
                return Result.fail("用户已经购买过一次");
            }

            VoucherOrder voucherOrder = new VoucherOrder();

            //扣减库存
            seckillVoucherService.update()
                    .setSql("stock = stock - 1")
                    .eq("voucher_id",voucherId).gt("stock",0)
                    .update();

            //设置订单Id
            long orderId = redisIdWorker.nextId("order");
            voucherOrder.setId(orderId);
            //设置优惠券Id
            voucherOrder.setVoucherId(voucherId);
            //设置用户Id
            voucherOrder.setUserId(userId);

            save(voucherOrder);

            //返回订单Id
            return Result.ok(orderId);
        } finally {
            //释放锁
            redisLock.unlock();
        }
    }

Redisson可重入锁原理(解决不可重入)

通过记录获取锁的数目,可以据此来判断当前是否是在最外围;

因为操作需要具有原子性,所以得采用Lua脚本进行编写

Lua实现获取锁

Lua脚本实现释放锁

可以深入Redisson获取锁与释放锁的流程,可以看到Lua脚本、

获取锁:

释放锁:

Redisson的深入理解(解决不可重试和超时释放)

锁重试:不是一直尝试获取锁,而是等待释放锁的信号量

WatchDog机制:简单来说就是每过一段时间去重置一下有效期;(如果负责储存这个分布式锁的Redisson节点宕机以后,而且这个锁正好处于锁住的状态时,这个锁会出现锁死的状态。为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。默认情况下,看门狗的检查锁的超时时间是30秒钟,也可以通过修改Config.lockWatchdogTimeout来另行指定。)

总结


解决主从一致性问题

如下图,如果按照下面方法来操作,获取锁时,如果redis的主节点宕机了,主从还未执行同步,而redis会从slave结点中选取作为主节点,但再次访问时会发现锁已经失效了

初始

 宕机后,选取主节点

multiLock(联锁)

需要同时获取成功才算成功,避免了主机宕机而导致锁失效的问题

总结

Redisson 是一个用于 Redis 的 Java 客户端,它不仅提供了对 Redis 原生命令的封装,还通过高级抽象简化了分布式系统的开发。Redisson 的设计目标是让开发者能够更方便地在分布式环境中使用 Redis,支持多种分布式数据结构和同步机制。 ### Redisson 的核心功能介绍 Redisson 提供了丰富的功能,包括但不限于以下内容: - **分布式对象**:Redisson 提供了多种分布式数据结构,如 `RMap`、`RSet`、`RList` 等,这些结构可以在多个节点之间共享,并且支持高效的并发访问。 - **分布式锁**:Redisson 提供了多种分布式锁实现,包括可重入锁(`RLock`)、读写锁(`RReadWriteLock`)等,这些锁可以用于协调多个节点之间的操作。 - **分布式服务**:Redisson 支持分布式任务调度(`RScheduledExecutorService`)和分布式事件监听器(`RTopic`),可以用于实现复杂的分布式系统逻辑。 - **对象存储**:Redisson 提供了 `RMapCache` 和 `RSetCache` 等缓存结构,支持过期时间的设置,适用于缓存场景。 - **流处理**:Redisson 提供了对 Redis Streams 的支持,可以用于处理实时数据流。 - **事务支持**:Redisson 支持 Redis 的事务机制,并提供了对分布式事务的封装。 - **集群支持**:Redisson 支持 Redis 集群模式,能够自动处理节点的扩容和数据迁移。 ### Redisson 的使用指南 #### 1. 添加依赖 首先,在项目中添加 Redisson 的依赖。以 Maven 为例,在 `pom.xml` 中添加以下内容: ```xml <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.17.6</version> <!-- 请根据需要选择合适的版本 --> </dependency> ``` #### 2. 配置 Redisson 客户端 Redisson 客户端可以通过配置文件或编程方式配置。以下是一个简单的编程配置示例: ```java import org.redisson.Redisson; import org.redisson.api.RedissonClient; import org.redisson.config.Config; public class RedissonExample { public static void main(String[] args) { // 创建配置 Config config = new Config(); // 设置 Redis 服务器地址 config.useSingleServer().setAddress("redis://127.0.0.1:6379"); // 创建 Redisson 客户端 RedissonClient redisson = Redisson.create(config); // 使用 Redisson 客户端 // ... // 关闭客户端 redisson.shutdown(); } } ``` #### 3. 使用分布式数据结构 Redisson 提供了多种分布式数据结构,以下是一个使用 `RMap` 的示例: ```java import org.redisson.api.RMap; import org.redisson.api.RedissonClient; public class RedissonMapExample { public static void main(String[] args) { // 创建 Redisson 客户端 RedissonClient redisson = Redisson.create(); // 获取分布式 Map RMap<String, String> map = redisson.getMap("myMap"); // 存储数据 map.put("key1", "value1"); map.put("key2", "value2"); // 获取数据 String value = map.get("key1"); System.out.println("Value for key1: " + value); // 关闭客户端 redisson.shutdown(); } } ``` #### 4. 使用分布式锁 Redisson 提供了强大的分布式锁功能,以下是一个使用 `RLock` 的示例: ```java import org.redisson.api.RLock; import org.redisson.api.RedissonClient; public class RedissonLockExample { public static void main(String[] args) { // 创建 Redisson 客户端 RedissonClient redisson = Redisson.create(); // 获取分布式锁 RLock lock = redisson.getLock("myLock"); try { // 获取锁 lock.lock(); // 执行需要锁的操作 System.out.println("Lock acquired, performing operations..."); } finally { // 释放锁 lock.unlock(); } // 关闭客户端 redisson.shutdown(); } } ``` #### 5. 使用分布式任务调度 Redisson 提供了分布式任务调度功能,以下是一个使用 `RScheduledExecutorService` 的示例: ```java import org.redisson.api.RScheduledExecutorService; import org.redisson.api.RedissonClient; import org.redisson.api.TaskId; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class RedissonScheduledExecutorExample { public static void main(String[] args) throws InterruptedException { // 创建 Redisson 客户端 RedissonClient redisson = Redisson.create(); // 获取分布式任务调度服务 RScheduledExecutorService executorService = redisson.getExecutorService("myExecutor"); // 提交任务 TaskId taskId = executorService.schedule(() -> { System.out.println("Task executed at " + System.currentTimeMillis()); }, 5, TimeUnit.SECONDS); // 等待任务执行完成 Thread.sleep(10000); // 关闭任务调度服务 executorService.shutdown(); // 关闭客户端 redisson.shutdown(); } } ``` ### 6. Redisson 的高级特性 Redisson 还支持许多高级特性,例如: - **分布式事件监听器**:可以通过 `RTopic` 实现发布/订阅模式。 - **分布式集合的过期时间**:例如 `RMapCache` 和 `RSetCache` 支持设置过期时间。 - **分布式流处理**:可以通过 `RStream` 处理 Redis Streams 数据。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值