【📕分布式锁通关指南 07】源码剖析redisson利用看门狗机制异步维持客户端锁

简介: Redisson 的看门狗机制是解决分布式锁续期问题的核心功能。当通过 `lock()` 方法加锁且未指定租约时间时,默认启用 30 秒的看门狗超时时间。其原理是在获取锁后创建一个定时任务,每隔 1/3 超时时间(默认 10 秒)通过 Lua 脚本检查锁状态并延长过期时间。续期操作异步执行,确保业务线程不被阻塞,同时仅当前持有锁的线程可成功续期。锁释放时自动清理看门狗任务,避免资源浪费。学习源码后需注意:避免使用带超时参数的加锁方法、控制业务执行时间、及时释放锁以优化性能。相比手动循环续期,Redisson 的定时任务方式更高效且安全。

引言

在上篇中,我们梳理了redisson的可重入锁的加锁流程,而加锁必然就会有锁续期的问题,那么看门狗机制是维持锁续期的关键。因此,在本篇中我们将剖析redisson中的看门狗机制究竟是如何实现的。

利用Watchdog机制异步维持客户端锁

看门狗机制是redisson解决锁续期问题而设置的,在前文中我们也有手写过,这里我们看看“正版”的是如何执行的。

1.首先,在获取锁时会触发看门狗机制:

private Long tryAcquire(long leaseTime, TimeUnit unit, long threadId) {
   
    Long ttl = null;
    // 如果未指定租约时间,则使用看门狗机制
    if (leaseTime != -1) {
   
        ttl = tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG);
    } else {
   
        // 使用默认的看门狗超时时间(默认30秒)
        ttl = tryLockInnerAsync(commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(),
                TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);
        // 启动看门狗
        scheduleExpirationRenewal(threadId);
    }
    return ttl;
}

2.看门狗启动逻辑:

private void scheduleExpirationRenewal(long threadId) {
   
    ExpirationEntry entry = new ExpirationEntry();
    ExpirationEntry oldEntry = EXPIRATION_RENEWAL_MAP.putIfAbsent(getEntryName(), entry);
    if (oldEntry != null) {
   
        oldEntry.addThreadId(threadId);
    } else {
   
        entry.addThreadId(threadId);
        // 重点:续期任务的调度
        renewExpiration();
    }
}

// 续期任务调度
private void renewExpiration() {
   
    // 创建异步续期任务
    Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
   
        @Override
        public void run(Timeout timeout) throws Exception {
   
            ExpirationEntry ee = EXPIRATION_RENEWAL_MAP.get(getEntryName());
            if (ee == null) {
   
                return;
            }

            // 通过Lua脚本延长锁的过期时间
            RFuture<Boolean> future = renewExpirationAsync(threadId);
            future.onComplete((success, e) -> {
   
                if (e != null) {
   
                    log.error("Can't update lock " + getName() + " expiration", e);
                    return;
                }

                if (success) {
   
                    // 如果续期成功,递归调用,实现循环续期
                    renewExpiration();
                }
            });
        }
        // 续期间隔为看门狗超时时间的1/3
    }, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS);

    ee.setTimeout(task);
}

3.续期的核心 Lua 脚本:

protected RFuture<Boolean> renewExpirationAsync(long threadId) {
   
    return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
        // 检查锁是否存在且被当前线程持有
        "if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
            // 重新设置过期时间
            "redis.call('pexpire', KEYS[1], ARGV[1]); " +
            "return 1; " +
        "end; " +
        "return 0;",
        Collections.singletonList(getName()),
        internalLockLeaseTime, // 默认30秒
        getLockName(threadId));
}

4.锁释放时清理看门狗:

void cancelExpirationRenewal(Long threadId) {
   
    ExpirationEntry task = EXPIRATION_RENEWAL_MAP.get(getEntryName());
    if (task == null) {
   
        return;
    }

    if (threadId != null) {
   
        task.removeThreadId(threadId);
    }

    if (threadId == null || task.hasNoThreads()) {
   
        // 取消定时任务
        task.getTimeout().cancel();
        EXPIRATION_RENEWAL_MAP.remove(getEntryName());
    }
}

让我们总结一下看门狗机制的工作流程:

  • 触发条件
    • 当调用 lock() 方法且未指定租约时间时
    • 默认使用 30 秒的看门狗超时时间
  • 核心原理
    • 在获取锁成功后,创建一个定时任务
    • 定时任务每隔 10 秒(默认超时时间的 1/3)执行一次
    • 通过 Lua 脚本检查锁是否还存在并延长过期时间
  • 续期策略
    • 每次续期都将过期时间刷新为 30 秒
    • 只要业务线程还持有锁,就会一直续期
    • 续期操作是异步的,不会阻塞业务线程
  • 自动清理
    • 当锁释放时,自动取消续期任务
    • 通过 EXPIRATION_RENEWAL_MAP 管理所有续期任务
  • 安全保证
    • 使用 Lua 脚本保证续期操作的原子性
    • 只有当前持有锁的线程才能续期成功
    • 如果业务异常导致线程中断,看门狗也会停止续期

另外,通过学习源码,我们要正确使用看门狗机制,我们需要注意:不要使用带超时参数的加锁方法,否则看门狗机制不会生效;确保业务执行时间不会过长,否则会产生大量续期操作;记得在完成业务后及时释放锁,避免资源浪费。

小结

看门狗机制的关键在于定时对锁的状态进行检查,回想下我们当时手撸是通过循环进行的,这里显然高明多了,采用的定时任务,并且定时任务的执行频率也是过期时间的1/3,执行效率也比我们采用循环的方式高得多。

目录
相关文章
|
2月前
|
NoSQL Java 调度
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
分布式锁是分布式系统中用于同步多节点访问共享资源的机制,防止并发操作带来的冲突。本文介绍了基于Spring Boot和Redis实现分布式锁的技术方案,涵盖锁的获取与释放、Redis配置、服务调度及多实例运行等内容,通过Docker Compose搭建环境,验证了锁的有效性与互斥特性。
185 0
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
|
4月前
|
NoSQL Java Redis
基于Redisson和自定义注解的分布式锁实现策略。
在实现分布式锁时,保证各个组件配置恰当、异常处理充足、资源清理彻底是至关重要的。这样保障了在分布布局场景下,锁的正确性和高效性,使得系统的稳健性得到增强。通过这种方式,可以有效预防并发环境下的资源冲突问题。
256 29
|
3月前
|
NoSQL Redis
分布式锁设计吗,你是如何实现锁类型切换、锁策略切换基于限流的?
本方案基于自定义注解与AOP实现分布式锁,支持锁类型(如可重入锁、公平锁等)与加锁策略(如重试、抛异常等)的灵活切换,并结合Redisson实现可重入、自动续期等功能,通过LUA脚本保障原子性,兼顾扩展性与实用性。
70 0
|
4月前
|
缓存 NoSQL Java
【📕分布式锁通关指南 11】源码剖析redisson之读写锁的实现
Redisson 的 `RedissonReadWriteLock` 提供了高效的分布式读写锁实现,适用于读多写少的场景。通过 Redis 与 Lua 脚本结合,确保读锁并行、写锁互斥,以及读写之间的互斥,保障了分布式环境下的数据一致性。它支持可重入、自动过期和锁释放机制,提升了系统并发性能与资源控制能力。
106 0
|
NoSQL 安全 调度
【📕分布式锁通关指南 10】源码剖析redisson之MultiLock的实现
Redisson 的 MultiLock 是一种分布式锁实现,支持对多个独立的 RLock 同时加锁或解锁。它通过“整锁整放”机制确保所有锁要么全部加锁成功,要么完全回滚,避免状态不一致。适用于跨多个 Redis 实例或节点的场景,如分布式任务调度。其核心逻辑基于遍历加锁列表,失败时自动释放已获取的锁,保证原子性。解锁时亦逐一操作,降低死锁风险。MultiLock 不依赖 Lua 脚本,而是封装多锁协调,满足高一致性需求的业务场景。
227 0
【📕分布式锁通关指南 10】源码剖析redisson之MultiLock的实现
|
3月前
|
存储 负载均衡 NoSQL
【赵渝强老师】Redis Cluster分布式集群
Redis Cluster是Redis的分布式存储解决方案,通过哈希槽(slot)实现数据分片,支持水平扩展,具备高可用性和负载均衡能力,适用于大规模数据场景。
297 2
|
3月前
|
存储 缓存 NoSQL
【📕分布式锁通关指南 12】源码剖析redisson如何利用Redis数据结构实现Semaphore和CountDownLatch
本文解析 Redisson 如何通过 Redis 实现分布式信号量(RSemaphore)与倒数闩(RCountDownLatch),利用 Lua 脚本与原子操作保障分布式环境下的同步控制,帮助开发者更好地理解其原理与应用。
237 6
|
4月前
|
存储 缓存 NoSQL
Redis核心数据结构与分布式锁实现详解
Redis 是高性能键值数据库,支持多种数据结构,如字符串、列表、集合、哈希、有序集合等,广泛用于缓存、消息队列和实时数据处理。本文详解其核心数据结构及分布式锁实现,帮助开发者提升系统性能与并发控制能力。
|
8月前
|
数据采集 存储 数据可视化
分布式爬虫框架Scrapy-Redis实战指南
本文介绍如何使用Scrapy-Redis构建分布式爬虫系统,采集携程平台上热门城市的酒店价格与评价信息。通过代理IP、Cookie和User-Agent设置规避反爬策略,实现高效数据抓取。结合价格动态趋势分析,助力酒店业优化市场策略、提升服务质量。技术架构涵盖Scrapy-Redis核心调度、代理中间件及数据解析存储,提供完整的技术路线图与代码示例。
819 0
分布式爬虫框架Scrapy-Redis实战指南
|
2月前
|
缓存 NoSQL 关系型数据库
Redis缓存和分布式锁
Redis 是一种高性能的键值存储系统,广泛用于缓存、消息队列和内存数据库。其典型应用包括缓解关系型数据库压力,通过缓存热点数据提高查询效率,支持高并发访问。此外,Redis 还可用于实现分布式锁,解决分布式系统中的资源竞争问题。文章还探讨了缓存的更新策略、缓存穿透与雪崩的解决方案,以及 Redlock 算法等关键技术。

热门文章

最新文章