【黑马点评日记】Redis分布式锁终极方案:Redisson全面解析(含源码解析)

🔥个人主页:北极的代码(欢迎来访)

🎬作者简介:java后端学习者

❄️个人专栏:苍穹外卖日记SSM框架深入JavaWeb

命运的结局尽可永在,不屈的挑战却不可须臾或缺!

前言:

前面我们手动的设置了Redis的分布式锁,并且经过一系列的优化(Lua 脚本 + UUID 解决了原子性释放别人锁 的问题),,虽然已经解决了"误删和原子性"这两个最基础的问题,但在"锁生命周期跟随业务、可重入、高效阻塞等待、公平性、多节点可靠性"这些高级特性上,还是有一定的缺陷的。

摘要:

本文深入分析了Redis分布式锁的手动实现与Redisson解决方案的差异。手动实现存在五大问题:固定锁过期时间导致业务超时风险、不可重入性、低效的自旋等待、缺乏公平性保证、单点故障风险。Redisson通过自动续期机制、可重入锁设计、高效阻塞等待、公平锁实现和RedLock算法,全面解决了这些问题。文章详细介绍了Redisson的配置方法、核心原理(如Hash结构存储锁信息、WatchDog自动续期机制)以及MultiLock联锁机制,为高并发场景下的分布式锁应用提供了专业级解决方案。

存在的问题:

1.锁过期时间固定 → 无法处理业务执行时间不确定

手动实现: 加锁时设置一个固定过期时间(比如 10 秒)。

问题:

  • 如果业务偶尔抖动(GC、慢查询、网络延迟),执行了 15 秒 → 锁在第 10 秒就没了,其他线程进来,在第 15 秒虽然不会删别人的锁(因为 UUID 不匹配),但后半段的执行已经失去了锁的保护,相当于无锁状态。

  • 如果为了保险设置很长的过期时间(比如 60 秒),那万一业务真卡死,其他线程要等 60 秒才能拿到锁,妥妥的故障。

Redisson 的做法:

自动续期(Watchdog)。只要业务还在跑,锁就会一直被续命,既不会提前释放,也不会卡死别人太久。

简单的说,我们自己实现的只能赌一个合适的过期时间,而 Redisson 能做到锁跟着业务走。


2. 不可重入(non-reentrant)

手动实现: 同一个线程第二次尝试获取同一把锁时,会被自己阻塞

场景:

java 复制代码
java

public void transfer() {
    lock("account:123");
    innerCheck();  // 里面又调用了 lock("account:123")
    unlock(...);
}

public void innerCheck() {
    lock("account:123");   // 死等自己
    // ...
}

问题: 同一个线程,在未释放锁的情况下再次加锁 → 死等自己,死锁

Redisson 的做法:

可重入锁,内部通过计数器和线程标识判断,同一线程重复加锁只增加计数,不会阻塞。


3. 无法阻塞等待锁(只能 try 或自旋)

手动实现:

  • 要么 setIfAbsent 立即返回成功/失败(非阻塞)

  • 要么自己写 while 循环 + sleep 自旋等待

问题:

  • 非阻塞:拿不到就放弃,很多场景你需要等一会儿再试

  • 自旋:要么浪费 CPU(无 sleep),要么响应延迟 + 浪费资源(固定 sleep)

Redisson 的做法:
tryLock(10, TimeUnit.SECONDS) 真正的阻塞等待,内部基于订阅 + 信号量实现,锁释放后立即唤醒,不浪费 CPU,响应快。


4. 没有公平性保证

手动实现: 谁抢得快谁得锁。

问题: 在高并发下,某些线程可能一直抢不到锁(饥饿),不是真正的"先来先得"。

Redisson 的做法:

提供公平锁实现,基于 Redis 队列保证请求顺序。


5. 单点/主从切换时的可靠性风险

手动实现: 假设 Redis 单机或主从。

问题:

  • 主节点宕机,从节点还没同步锁数据 → 锁丢失,多个客户端同时拿到同一把锁

  • 你无法用 RedLock 算法解决这个问题

Redisson 的做法:

内置 RedLock(红锁)实现,需要向多个独立 Redis 节点申请锁,半数以上成功才算成功,能容忍部分节点故障。


总结对比表

问题 手动实现 Redisson
原子性 + 防误删 ✅ 已解决(Lua + UUID) ✅ 有
业务执行时间不确定(锁提前释放) ❌ 固定过期时间,风险存在 ✅ 自动续期
可重入 ❌ 同一线程自己锁自己 ✅ 支持
阻塞等待锁 ❌ 无 / 自旋低效 ✅ 高效阻塞 + 唤醒
公平锁 ❌ 无 ✅ 有
主从切换 / 多节点一致性 ❌ 单点 / 异步复制风险 ✅ RedLock

什么时候必须上 Redisson

场景 建议
低并发、业务简单、锁持有时间确定且很短 SET NX EX + Lua 解锁 够用
高并发、业务执行时间不确定 必须上 Redisson(需要续期)
需要可重入锁(一个方法调另一个方法) 必须上 Redisson(自己实现很麻烦)
需要阻塞等待锁,且对性能有要求 必须上 Redisson(自旋 + 休眠效率低)
需要公平锁、读写锁、红锁等高级特性 必须上 Redisson

代码实现Redisson:

1.引入依赖:

XML 复制代码
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.13.6</version>
        </dependency>

这里需要注意的是,如果是我们引入的依赖爆红的话,可能是maven没刷新加载,刷新完我们可以看到侧面的相应依赖项:

2.在配置类中配置

告诉 Spring 如何创建 RedissonClient 这个对象,并把它放进 Spring 容器管理。

更直白地说:配置类就是教 Spring 怎么 new 这个对象。

java 复制代码
package com.hmdp.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;

@Configuration

public class RedissonConfig {
@Bean
   public RedissonClient redissonClient(){

    //创建配置
    Config config=new Config();
    config.useSingleServer().setAddress("redis://127.0.0.1:6379");

       return Redisson.create(config);
   }


}

这里标上配置类的注解,@Configuration /标记这是一个配置类

然后加上**@Bean交给Spring管理**,这个方法返回的对象要放进容器

这里的Redis连接的是我们自己的主机地址,记得别写错,设置密码的自己也可以加上。

这里需要注意的是

如果我们已经导入了依赖并且maven也已经刷新了,RedisClient仍旧报错,这时我们只需要**清理一下Idea的缓存,**有可能是

Maven 刷新信号没传给索引 :我们点了刷新,依赖下载好了,但 IDEA 的索引更新任务可能因为某些原因没触发或没完成

并发写冲突 :Maven 在后台下载依赖(往磁盘写),IDEA 同时在读依赖(建索引),可能锁文件或状态不一致

因此我们清楚缓存:重启后,IDEA 发现缓存是空的,就会重新扫描整个项目的 classpath(包括所有的 Maven 依赖),重新生成索引。

总之:

写配置类是为了让 Spring 认识并管理那些不是我们写的类(比如 RedissonClient)。

@Service Spring 能自动发现,用 RedissonClient 必须通过 @Bean 告诉 Spring 怎么创建它。

3.实现类实现:

配置类写好之后,下一步就是在实现类(比如 Service)里使用 RedissonClient 来加锁和解锁。

注入:(Spring 会自动把配置类里创建的那个对象拿过来)

java 复制代码
    @Resource
    private RedissonClient redissonClient;
java 复制代码
@Service
public class OrderService {
    
    // 注入 RedissonClient(Spring 会自动把配置类里创建的那个对象拿过来)
    @Autowired
    private RedissonClient redissonClient;
    
    public void createOrder(String orderId) {
        // 1. 获取锁(根据业务 key 命名)
        RLock lock = redissonClient.getLock("lock:order:" + orderId);
        
        // 2. 加锁(阻塞等待,带自动续期)
        lock.lock();
        
        try {
            // 3. 执行业务逻辑
            // 例如:查询库存、扣减库存、创建订单等
            System.out.println("执行业务,orderId: " + orderId);
            Thread.sleep(5000);  // 模拟业务执行
        } finally {
            // 4. 释放锁(一定要在 finally 里释放)
            lock.unlock();
        }
    }
}

获取锁
boolean isLock = lock.tryLock();这里参数是干嘛的

方法 行为 适用场景
tryLock() 只试一次,被占用立即返回 false 能接受失败、需要快速响应的场景(如秒杀提示"已售罄")
tryLock(10, TimeUnit.SECONDS) 最多等 10 秒,期间会不断重试 可以等待、希望最终能执行成功的场景
lock() 无限等待,直到拿到锁 必须执行成功、不介意阻塞的场景

源码解析:

Redisson可重入锁的原理:

Redisson 的实现原理可以概括为:用 Redis 的 Hash 结构存储锁的持有者和重入次数

普通的分布式锁,用 SET NX 实现的那个,在 Redis 里存的是一个字符串,比如 "锁的持有者:线程A"

如果同一个线程再次去拿这把锁:

  1. 线程A 已经持有锁,Redis 里已经有这个 key 了

  2. 线程A 再次执行 SET NX,发现 key 已存在

  3. 线程A 认为自己没拿到锁,就会阻塞等待

  4. 但持有锁的就是它自己,于是它永远等不到锁释放 → 死锁

这就是不可重入的问题。


Redisson 的解决方案

Redisson 不存简单的字符串,而是用 Hash(哈希表) 来存锁的信息。

Hash 的结构:

  • 大 Key:锁的名字,比如 "myLock"

  • 里面的小 Field:持有锁的线程的唯一标识

  • 里面的 Value:这个线程加锁的次数(计数器)

举个例子:

text

复制代码
Hash "myLock" 的内容:
  - field = "uuid-123:线程ID-45"  
  - value = 3

意思是:uuid-123:线程ID-45 这个线程,已经对 myLock 这把锁加了 3 次锁。

加锁的流程

第一次加锁:

  1. 检查 Hash myLock 是否存在 → 不存在

  2. 创建 Hash,设置 field 为当前线程标识,value 设为 1

  3. 设置过期时间(比如 30 秒)

同一个线程第二次加锁:

  1. 检查 Hash myLock 是否存在 → 存在

  2. 检查 Hash 里有没有当前线程的 field→ 有

  3. 不是创建新锁,而是把 value 加 1(从 1 变成 2)

  4. 刷新过期时间(重新计时 30 秒)

第三次加锁:

  • 同样,value 从 2 变成 3,再刷新过期时间

关键点: 后面的加锁不会创建新的锁条目,只是把计数器往上加,同时把锁的存活时间重新计时。

解锁的流程

第一次解锁:

  1. 找到 Hash myLock

  2. 找到当前线程对应的 field

  3. 把 value 减 1(从 3 变成 2)

  4. 因为 value 还大于 0,说明还有重入,所以不删锁,只刷新过期时间

第二次解锁:

  • value 从 2 变成 1,还是不删锁

第三次解锁:

  • value 从 1 变成 0

  • 这时才真正删除 Redis 里的 Hash,锁被释放

关键点: 解锁多少次,计数器就减多少次。只有减到 0 时,锁才会真正消失。

类比:

普通锁像一扇门:

  • 第一次进去,锁上门

  • 第二次想进去,发现门锁着,以为别人在里面,就在门口等

  • 但其实是自己锁的,永远等不到

Redisson 的可重入锁像一个计数器:

  • 第一次进去,计数器显示 1

  • 第二次进去,计数器变成 2(门不关)

  • 第三次进去,计数器变成 3

  • 出来一次,计数器减 1

  • 直到计数器变回 0,门才真正锁上

  1. 用 Hash 存储:大 Key 是锁名,小 Field 是线程标识,Value 是重入次数

  2. 同线程重入:不阻塞,只是把次数加 1,同时刷新过期时间

  3. 真正释放:每次解锁次数减 1,只有减到 0 才删除 Redis 中的锁

这样既解决了同一线程重复加锁的死锁问题,又保证了锁的寿命跟业务执行时间走,不会提前过期。


Redisson的锁重试和WatchDog机制原理:

这两个机制解决了分布式锁中的两个痛点:

  1. 锁重试:拿不到锁时怎么办(阻塞等待 vs 立即返回)

  2. WatchDog:业务没执行完,锁过期了怎么办自动续期)


一、锁重试机制
1. 三种获取锁的方式
方法 行为 适用场景
lock() 无限等待,直到拿到锁 必须执行成功的任务
tryLock() 只试一次,拿不到立即返回 false 可接受失败的场景
tryLock(waitTime, leaseTime, unit) 最多等待 waitTime,期间不断重试 希望等待但不想无限等
2. tryLock(waitTime, leaseTime, unit) 的重试原理

场景: 线程 A 持有锁,线程 B 来拿锁

线程 B 执行:

java

复制代码
boolean locked = lock.tryLock(10, 30, TimeUnit.SECONDS);
// 最多等 10 秒,拿到锁后锁的有效期是 30 秒

内部流程:

text

复制代码
线程 B 尝试加锁
    ↓
Redis:锁被线程 A 占着
    ↓
线程 B 不是立即返回失败,而是订阅 Redis 的频道(发布订阅)
    ↓
线程 B 阻塞等待(不浪费 CPU)
    ↓
线程 A 释放锁时,发布一条消息到该频道
    ↓
线程 B 收到消息,立即重新尝试加锁
    ↓
如果成功,返回 true;如果失败,继续等待
    ↓
超过 10 秒还没成功 → 返回 false

关键点:

  • 不是轮询:用 Redis 的发布订阅,锁释放时主动通知,响应快

  • 不占 CPU:等待期间线程是阻塞的,不会空转

  • 有超时:不会无限等下去

3. 重试的间隔

Redisson 的重试不是固定间隔,而是:

  • 第一次失败后,订阅频道,进入阻塞等待

  • 收到释放通知后,立即重新尝试

  • 如果没有收到通知(网络问题等),也会有一个小的退避策略


二、WatchDog 机制(自动续期)

1. 解决什么问题

遇到的问题:

  • 设置锁过期时间 10 秒

  • 业务执行了 15 秒

  • 第 10 秒时锁自动释放,其他线程进来,数据错乱

WatchDog 就是解决这个问题的:业务没执行完,锁就不会过期。

2. WatchDog 的工作原理

默认行为:

  • 调用 lock.lock()tryLock()(不传 leaseTime)时

  • Redisson 会给锁设置一个默认过期时间(30 秒

  • 同时启动一个后台线程(WatchDog)

WatchDog 的工作:

text

复制代码
锁被成功获取(过期时间 30 秒)
    ↓
WatchDog 线程启动
    ↓
每 10 秒检查一次(30 秒的 1/3)
    ↓
检查:当前线程是否还持有这把锁?
    ↓
如果是 → 把锁的过期时间重置为 30 秒(续期)
    ↓
如果否 → 停止续期

时间线示例:

text

复制代码
0s    10s   20s   30s   40s   50s   60s
|-----|-----|-----|-----|-----|-----|
锁获取                      
      ↑续期  ↑续期  ↑续期  ↑续期  ↑续期
      (每10秒续期到30秒)
                                    ↑
                                业务结束,释放锁

只要业务还在跑,锁的过期时间永远被推到"当前时间 + 30 秒"。

3. WatchDog 的开启条件
加锁方式 WatchDog 是否启动
lock() ✅ 启动
tryLock() ✅ 启动
tryLock(waitTime, TimeUnit.SECONDS)(不传 leaseTime) ✅ 启动
tryLock(waitTime, leaseTime, unit)(传了 leaseTime) ❌ 不启动
lock(leaseTime, unit)(传了 leaseTime) ❌ 不启动

规则: 如果你手动指定了锁的持有时间(leaseTime),Redisson 就认为你知道自己在做什么,不会帮你续期。时间到了锁就释放,不管业务是否完成。

4. WatchDog 的停止条件

WatchDog 会在以下情况停止:

  1. 业务执行完,调用 unlock() 释放锁

  2. 当前线程不再持有锁(被其他情况释放了)

  3. Redisson 客户端关闭

java

复制代码
RLock lock = redissonClient.getLock("myLock");

// 尝试加锁,最多等 5 秒(重试机制),拿到后锁有效期 30 秒(WatchDog 会续期)
boolean locked = lock.tryLock(5, TimeUnit.SECONDS);

if (locked) {
    try {
        // 业务执行中...
        // WatchDog 每 10 秒检查并续期
        // 业务执行 10 分钟也不会锁过期
    } finally {
        lock.unlock();  // 释放锁,WatchDog 停止
    }
}

流程图:

text

复制代码
线程尝试获取锁
    ↓
锁被占用?
    ├─ 否 → 拿到锁,启动 WatchDog
    │         ↓
    │      执行业务
    │         ↓
    │      WatchDog 每 10 秒续期
    │         ↓
    │      业务完成,unlock,停止 WatchDog
    │
    └─ 是 → 订阅频道,阻塞等待
              ↓
           收到释放通知
              ↓
           重新尝试加锁
              ↓
           成功 → 拿到锁,启动 WatchDog
           超时 → 返回 false

功能 我们自己实现的锁 Redisson
拿不到锁怎么办 要么立即失败,要么自己写 while 循环 内置发布订阅,阻塞等待,不占 CPU
重试间隔 自己写 Thread.sleep(),固定间隔 收到通知立即重试,响应快
锁过期问题 设置固定时间,业务超时锁就没了 WatchDog 自动续期,锁跟着业务走
续期实现 需要自己写定时任务 内置后台线程,自动续期

需要注意的坑
1. 手动指定 leaseTime 会关闭 WatchDog

java

复制代码
// ❌ WatchDog 不启动,30 秒后锁强制释放
lock.lock(30, TimeUnit.SECONDS);

// ✅ WatchDog 启动,自动续期
lock.lock();

// ✅ 也是不启动(传了 leaseTime)
lock.tryLock(10, 30, TimeUnit.SECONDS);
2. 业务时间超过 WatchDog 续期间隔

WatchDog 每 10 秒续一次,如果业务在 10 秒内完成,续期不会发生。如果业务超过 10 秒,续期会在第 10 秒时执行,把锁延长到 30 秒。

极端情况: 业务在第 10 秒刚好完成,续期还没来得及执行,锁会怎样?------ 业务完成了,锁也会正常释放,没问题。

3. 网络断开时 WatchDog 的行为

如果 Redisson 和 Redis 断开连接:

  • WatchDog 无法续期

  • 锁会在 30 秒后自动释放

  • 这是合理的设计:宁可让锁提前释放,也不能让锁永远锁住


总结

机制 解决的问题 实现方式
锁重试 拿不到锁时如何等待 Redis 发布订阅 + 阻塞等待,有超时控制
WatchDog 业务没执行完锁就过期 后台线程定期检查并续期,默认每 10 秒续到 30 秒
  • 锁重试让我们不用自己写轮询,等待锁释放时能被立即唤醒

  • WatchDog让我们不用担心业务执行时间超锁,锁会自动跟着业务走

这两个机制加在一起,就是 Redisson 能成为生产级分布式锁方案的核心原因。


Redisson MultiLock 的原理

MultiLock 是 Redisson 提供的联锁 机制,它的作用是:同时锁定多个资源,要么全部锁住,要么一个都不锁

1、什么时候需要 MultiLock

场景: 一个操作需要同时操作多个独立的资源,必须保证所有资源都被锁定,才能开始执行。

例子: 跨账户转账

  • 从账户 A 扣钱

  • 往账户 B 加钱

为了保证数据一致,必须同时锁定账户 A 和账户 B。如果只锁 A,不锁 B,可能出现:A 扣了钱,但 B 没加上(因为 B 被别的操作锁着)。

MultiLock 的作用: 把对多个锁的加锁操作变成一个原子操作。

2、MultiLock 的核心原则

MultiLock 实现的是**"多锁合一"**的逻辑:

原则 说明
全部成功才算成功 必须所有锁都获取成功,整个加锁才算成功
部分失败则全部回滚 只要有一个锁没拿到,已经拿到的锁全部释放
统一过期时间 所有锁使用相同的过期时间,同时释放
3、MultiLock 的使用方式

java

复制代码
// 1. 创建多个独立的锁
RLock lock1 = redissonClient.getLock("lock:account:A");
RLock lock2 = redissonClient.getLock("lock:account:B");
RLock lock3 = redissonClient.getLock("lock:account:C");

// 2. 创建 MultiLock,把多个锁组合在一起
RLock multiLock = redissonClient.getMultiLock(lock1, lock2, lock3);

// 3. 像使用普通锁一样使用 MultiLock
multiLock.lock();  // 同时锁住 A、B、C

try {
    // 执行跨账户操作
    transferMoney();
} finally {
    multiLock.unlock();  // 同时释放 A、B、C
}

注意: 调用 multiLock.lock() 时,Redisson 会逐个去获取 lock1lock2lock3,而不是一次性的原子命令(因为 Redis 不支持跨 key 的原子操作)。

4、MultiLock 的加锁流程

text

复制代码
调用 multiLock.lock()
    ↓
创建一个列表,记录成功获取的锁
    ↓
遍历所有锁(lock1, lock2, lock3...)
    ↓
对当前锁尝试加锁
    ├─ 加锁成功 → 把锁加入"成功列表",继续下一个
    └─ 加锁失败 → 进入重试等待(有超时时间)
         ↓
    如果最终所有锁都成功 → 返回 true
    ↓
    【如果任何一个锁加锁失败(超时或异常)】
         ↓
    遍历"成功列表",对所有已成功获取的锁执行 unlock
         ↓
    抛出异常或返回 false

关键点: MultiLock 不是原子的,但通过"全部成功才保留,部分失败就回滚"的机制,实现了逻辑上的原子性

5、锁重试和 WatchDog 在 MultiLock 中的行为
1. 锁重试

java

复制代码
// 最多等待 10 秒,拿到所有锁后锁的有效期是 30 秒
boolean locked = multiLock.tryLock(10, 30, TimeUnit.SECONDS);

重试逻辑:

  • 遍历每个锁时,对单个锁应用等待时间

  • 如果一个锁拿不到,MultiLock 会在剩余时间内不断重试这个锁

  • 如果某个锁一直拿不到,最终超时,则释放所有已获取的锁

2. WatchDog 的行为

java

复制代码
multiLock.lock();  // 不传 leaseTime,启动 WatchDog

WatchDog 在 MultiLock 中的特殊之处:

  • 每个子锁独立续期 :WatchDog 会对 MultiLock 中的每一个锁分别进行续期

  • 正确逻辑multiLock.lock() 内部调用每个子锁的 lock(),每个子锁都有自己的 WatchDog。只要 MultiLock 还没被 unlock,每个子锁的 WatchDog 都会独立续期。

  • 潜在问题: 如果所有子锁都不传 leaseTime,那么会有 N 个 WatchDog 线程在运行(每个子锁一个),资源消耗会翻倍。


    6、MultiLock 的解锁流程

    text

    复制代码
    调用 multiLock.unlock()
        ↓
    遍历所有子锁
        ↓
    对每个子锁执行 unlock
        ↓
    如果有锁在 unlock 时抛出异常
        ↓
    继续尝试解锁其他锁(不能因为一个失败就停止)
        ↓
    最终汇总异常情况

    关键点: 解锁不会因为某个锁失败就停止,会尽可能释放所有锁。


    7、MultiLock 的局限性
    局限性 说明
    不是分布式事务 MultiLock 只能保证"锁"的一致性,不能回滚业务数据。比如 A 扣钱成功了,B 加钱失败了,MultiLock 不会帮你自动回滚 A 的扣钱操作。
    性能开销 加锁时间 = N × 单锁加锁时间,锁越多越慢
    可靠性降低 N 个锁中任意一个 Redis 节点故障,整个 MultiLock 就无法工作
    WatchDog 膨胀 每个子锁都有自己的 WatchDog 线程,锁多了线程数会翻倍

    8、和 RedLock 的区别

    很多人会把 MultiLock 和 RedLock 搞混,它们完全不同:

    对比 MultiLock RedLock
    目的 同时锁定多个不同的资源 同一个资源在多个 Redis 节点上锁定
    锁的对象 lock1, lock2, lock3(不同业务资源) 同一个锁名,多个 Redis 实例
    使用场景 跨账户转账、批量操作 高可靠性分布式锁(防止主从切换丢锁)

    MultiLock 示例: 锁住账户 A、账户 B、账户 C(三个不同的业务资源)

    RedLock 示例: 在 Redis-1、Redis-2、Redis-3 三个节点上,锁住同一个"订单 123"(同一个资源,多个节点备份)


结语:如果对你有帮助,请点赞,关注,收藏,你的支持就是我最大的鼓励!

相关推荐
m0_741173331 小时前
MySQL导入大SQL文件报错怎么办_拆分文件与优化系统参数
jvm·数据库·python
苏渡苇1 小时前
Redis 核心数据结构(二)——List 与消息队列
数据结构·redis·list·redis发布订阅
Achou.Wang1 小时前
go语言并发编程
java·开发语言·golang
BullSmall1 小时前
Redis AOF 文件损坏报错:完整修复方案
数据库·redis·缓存
Amnesia0_01 小时前
磁盘文件系统
linux·运维·数据库
数据库知识分享者小北1 小时前
智能运维+多模型服务能力,阿里云 RDS AI 助手旗舰版正式上线!
运维·数据库·阿里云·阿里巴巴·rds·智能运维
小王师傅661 小时前
【Java结构化梳理】泛型-初步了解-中
java·开发语言
CQU_JIAKE1 小时前
[q]4.25
java·开发语言·前端
Albert Edison1 小时前
【RabbitMQ】RPC 通信(使用案例)
分布式·rpc·rabbitmq