Redis实现分布式锁的原理

一、为什么需要分布式锁

分布式系统 中,多个节点或服务实例可能同时修改同一份共享资源(例如数据库、库存、订单),

为防止并发修改、超卖、数据不一致 ,我们需要一种 跨节点的"互斥"机制

在单机中可用 synchronizedReentrantLock

但在多机(分布式)环境下,它们无法保证互斥性。

这时就需要分布式锁


⚙️ 二、Redis 分布式锁的基本原理

Redis 本身是一个单线程 、支持原子操作的 KV 数据库,非常适合实现分布式锁。

核心思想:

使用 Redis 的原子命令 SETNX(Set if Not Exists)

  • 过期时间(防止死锁)
    来确保在分布式环境中,同一时刻只有一个客户端能获得锁

🔑 三、最常见的实现方式(单节点版本)

🧠 思路:

  1. 加锁 :使用 SET key value NX PX expireTime

    • NX:只有 key 不存在时才能设置成功(防止被覆盖)
    • PX:设置过期时间(毫秒)
  2. 释放锁:只有锁的持有者才能删除锁(防止误删)

🔑 四、 Redisson 高级实现(推荐)

Redisson 是官方推荐的 Java Redis 客户端之一,封装了稳定的分布式锁逻辑

Redisson 实现了:

  • 自动续期机制(Watchdog)
  • 支持 RedLock 多节点锁算法
  • 防止主从切换导致锁丢失

RedLock 的基本思想

假设有 5 个独立的 Redis 节点(N = 5),RedLock 的核心流程是:

  1. 客户端向所有 Redis 节点尝试获取锁**,每个节点的锁具有 唯一标识(UUID)过期时间(TTL)

  2. 获取锁成功的条件:

    • 客户端在多数节点(> N/2,比如至少3个节点) 成功获取到锁。
    • 并且总耗时 < TTL
  3. 业务执行完毕释放锁:

    • 客户端向获取成功的 Redis 节点发送解锁请求。
    • 每个节点只删除与自己 UUID 匹配的锁,保证安全释放。
  4. 如果获取锁失败(未超过多数节点或超时),回滚已获取的锁

js 复制代码
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class RedissonManager {

    private static RedissonClient redissonClient;

    static {
        Config config = new Config();
        // Redis 集群模式配置
        config.useClusterServers()
              .addNodeAddress("redis://127.0.0.1:7000", "redis://127.0.0.1:7001", "redis://127.0.0.1:7002");
        redissonClient = Redisson.create(config);
    }

    public static RedissonClient getClient() {
        return redissonClient;
    }
}
js 复制代码
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import java.util.concurrent.TimeUnit;

public class DistributedLockExample {

    public static void main(String[] args) {
        RedissonClient redisson = RedissonManager.getClient();

        // 获取锁对象
        RLock lock = redisson.getLock("myLock");

        try {
            // 尝试加锁,最多等待3秒,锁超时10秒自动释放
            boolean isLocked = lock.tryLock(3, 10, TimeUnit.SECONDS);
            if (isLocked) {
                try {
                    // 加锁成功,执行业务逻辑
                    System.out.println("获得锁,执行业务逻辑");
                    Thread.sleep(5000); // 模拟业务操作
                } finally {
                    lock.unlock(); // 释放锁
                    System.out.println("释放锁");
                }
            } else {
                System.out.println("获取锁失败,其他线程在执行");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
相关推荐
东风破_1 天前
大前端手里的 Next.js:从 #root 到 SEO,一份 HTML 的两种命运
前端·后端
IT_陈寒1 天前
Vue的v-for不听话?我被这个Key的坑整懵了
前端·人工智能·后端
众人皆醒我独醉1 天前
训练加速实战:Flash Attention、Gradient Checkpointing 与数据流水线
后端·面试·gpu
阿黎梨梨1 天前
Next.js 全栈开发:从 SPA 的痛点到 SSR 的破局之道
前端·后端
名字还没想好☜1 天前
Go 的 unsafe.Pointer 实战:零拷贝 []byte↔string 转换与三条铁律
开发语言·后端·golang·go·unsafe
老孙讲技术1 天前
周末档期厨房爆单,带宽账单也爆了——不是直播难,是主码流 + always 计划在烧钱
后端·物联网
老孙讲技术1 天前
校园开放日前夜才说要「全校透明」?我用轻应用把 9 路教室预览和回放嵌进了校园后台
后端·物联网
Python私教1 天前
AI Agent 可观测性实战:从 correlationId 到失败时间线
人工智能·后端
用户7791666846541 天前
给 Agent 开权限:身份不能进模型的上下文
后端
掘金一周1 天前
掘友们,你们现在下班了都玩啥游戏?| 沸点周刊 8.13
前端·人工智能·后端