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();
        }
    }
}
相关推荐
阿豪啊4 小时前
Prisma ORM 入门指南:从零开始的全栈技能学习之旅
javascript·后端·node.js
optimistic_chen4 小时前
【Java EE进阶 --- SpringBoot】统一功能处理(拦截器)
spring boot·后端·java-ee·log4j·拦截器
苏三的开发日记4 小时前
什么是幂等,幂等如何实现
后端
逻极5 小时前
变量与可变性:Rust中的数据绑定
开发语言·后端·rust
一缕茶香思绪万堵5 小时前
028.爬虫专用浏览器-抓取#shadowRoot(closed)下
java·后端
panco681205 小时前
Ristretto - Golang高性能内存缓存管理库
后端
Cache技术分享6 小时前
226. Java 集合 - Set接口 —— 拒绝重复元素的集合
前端·后端
代码扳手6 小时前
Go 开发的“热更新”真相:从 fresh 到真正的零停机思考
后端·go
9号达人6 小时前
认证方案的设计与思考
java·后端·面试