生产可用的 Redis 分布式锁完整实现

Redis 分布式锁是分布式系统中解决并发安全 的核心方案,生产环境绝对不能用简单的 SETNX ,必须满足:加锁原子性、防死锁、防误删、可重入、高可用

我会给你可直接落地生产的 Java 实现(Redisson 最佳实践) + 核心原理 + 避坑指南


一、生产级 Redis 分布式锁核心要求

  1. 互斥性:同一时间只有一个客户端持有锁
  2. 防死锁:客户端宕机也能自动释放锁(必须设置过期时间)
  3. 原子性:加锁 + 设置过期必须是原子操作
  4. 防误删:只能删除自己加的锁,不能删除别人的
  5. 可重入:同一个线程/客户端可重复加锁(避免死锁)
  6. 高可用:Redis 集群/主从下依然可靠
  7. 容错性:锁等待、重试、超时机制

二、绝对不要用的错误实现

以下写法生产环境必出问题,严禁使用:

java 复制代码
// 错误1:加锁和过期时间非原子,客户端宕机直接死锁
redis.setnx(key, value);
redis.expire(key, 30);

// 错误2:没有唯一标识,会误删别人的锁
redis.del(key);

// 错误3:判断和删除非原子,并发下依然误删
if (redis.get(key).equals(value)) {
    redis.del(key); // 这里锁已过期,会删别人的锁
}

三、生产标准实现:基于 Redisson(推荐)

Redisson 是 Redis 官方推荐的分布式锁框架,完美实现了所有生产特性:

  • 原子加锁/解锁
  • 锁自动续期(看门狗机制)
  • 可重入锁
  • 公平锁/读写锁
  • 红锁(解决 Redis 主从切换锁丢失问题)
  • 支持集群、哨兵、单机模式

1. 依赖引入(Maven)

xml 复制代码
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.29.0</version> <!-- 稳定版 -->
</dependency>

2. Redisson 配置(application.yml)

yaml 复制代码
spring:
  redis:
    host: 127.0.0.1
    port: 6379
    password: your-password
    database: 0

3. 生产可用工具类

java 复制代码
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * 生产级 Redis 分布式锁工具类(基于 Redisson)
 */
@Component
public class RedisDistributedLock {

    @Resource
    private RedissonClient redissonClient;

    /**
     * 加锁
     * @param lockKey 锁key
     * @param waitTime 等待获取锁的时间
     * @param leaseTime 锁自动释放时间(不传启用看门狗自动续期)
     * @return 是否加锁成功
     */
    public boolean lock(String lockKey, long waitTime, long leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 尝试加锁,最多等待waitTime,上锁后leaseTime秒自动解锁
            return lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
    }

    /**
     * 解锁(仅自己的锁可解)
     */
    public void unlock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        // 校验锁归属 + 解锁,原子操作
        if (lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }
}

4. 业务代码使用示例

java 复制代码
@Service
public class OrderService {

    @Resource
    private RedisDistributedLock distributedLock;

    public void createOrder(Long userId) {
        String lockKey = "order:lock:" + userId;
        // 等待3秒,锁10秒自动释放
        boolean lockSuccess = distributedLock.lock(lockKey, 3, 10);
        
        if (!lockSuccess) {
            throw new RuntimeException("请求太频繁,请稍后再试");
        }

        try {
            // 核心业务逻辑(扣库存、创建订单...)
            System.out.println("获取锁成功,执行业务");
        } finally {
            // 必须在 finally 中解锁
            distributedLock.unlock(lockKey);
        }
    }
}

四、核心生产特性详解

1. 看门狗自动续期(避免业务未执行完锁过期)

  • 如果不指定 leaseTime ,Redisson 会启用看门狗
  • 默认每 30s 检查一次,只要线程没释放,就自动延长锁时间
  • 彻底解决:业务执行时间 > 锁过期时间导致的锁失效问题

2. 防误删原理

  • 每个锁携带唯一客户端ID + 线程ID
  • 解锁时校验:只有自己的锁才能解锁
  • 解锁是 Lua 脚本原子操作,无并发安全问题

3. 可重入锁原理

  • 锁内部维护计数器,同一线程重复加锁计数+1,解锁计数-1
  • 计数为0时真正释放锁
  • 避免同一线程重复加锁导致死锁

五、高可用终极方案:Redlock 红锁

适用场景

金融、支付等绝对不允许锁丢失的核心业务(解决 Redis 主从切换锁丢失问题)

原理

  • N 个独立 Redis 节点(无主从)申请锁
  • 超过半数节点加锁成功,才算加锁成功
  • 解锁时向所有节点解锁

实现

java 复制代码
// 红锁使用(多独立Redis节点)
RLock lock1 = redissonClient1.getLock(key);
RLock lock2 = redissonClient2.getLock(key);
RLock lock3 = redissonClient3.getLock(key);
RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
redLock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);

六、生产环境最佳实践

  1. 锁粒度尽可能小:只锁核心资源,提升并发性能
  2. 必须设置等待时间:避免无限阻塞
  3. 解锁必须放在 finally:保证无论如何都释放锁
  4. 核心业务用红锁:普通业务用普通分布式锁
  5. 监控锁竞争:添加日志、监控,排查锁等待、死锁问题
  6. 避免长业务持有锁:锁内只做原子操作,不做远程调用/慢查询

总结

  1. 生产环境必须用 Redisson,不要手写 Redis 锁
  2. 核心保障:原子加锁、唯一标识、Lua 解锁、看门狗续期、可重入
  3. 高可用:普通业务用普通锁,核心业务用 Redlock 红锁
  4. 代码可直接复制到生产环境使用,无坑、稳定可靠
相关推荐
Nturmoils10 小时前
订单列表慢查询,先看 WHERE、ORDER BY 和 LIMIT
数据库
渣波14 小时前
拒绝 SQL 焦虑!手把手带你用 NestJS + Prisma + DTO 写出“防弹”级后端代码
javascript·数据库·后端
倔强的石头_2 天前
KingbaseES 新版MySQL 兼容版体验:旧版迁移 + 功能实测
数据库
用户3169353811834 天前
Java连接Redis
redis
倔强的石头_5 天前
《Kingbase护城河》——数据库存储空间全景探测与精细化瘦身实战
数据库
冬奇Lab5 天前
每日一个开源项目(第134篇):Zvec - 阿里开源的嵌入式向量数据库,向量搜索界的 SQLite
数据库·人工智能·llm
ClouGence5 天前
Oracle CDC 架构优化:从主库直连到 DataGuard 备库同步
数据库·后端·oracle
无响应de神6 天前
三、用户与权限管理
数据库·mysql
小小工匠6 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
麦聪聊数据6 天前
数据服务化时代:企业数据能力输出的核心路径
数据库