Redis 实现分布式锁详解

什么是分布式锁?

分布式锁是一种跨进程、跨机器的互斥机制,它允许多个服务实例竞争一个共享资源的独占权。只有持有锁的服务实例才能操作该资源,其他实例必须等待锁释放后才能继续尝试获取锁。

分布式锁的核心要求包括:

  1. 互斥性:同一时间只有一个客户端能够持有锁。
  2. 高可用性:即使部分节点宕机,锁服务仍然可用。
  3. 安全性:锁不会被错误地分配给多个客户端。
  4. 容错性:如果客户端崩溃或网络中断,锁应能自动释放。

使用 Redis 实现分布式锁的基本原理

Redis 提供了原子操作(如 SETNX 和 Lua 脚本),可以用来实现分布式锁。以下是实现的基本步骤:

  1. 加锁

    • 使用 Redis 的 SETNX 命令尝试设置一个键值对,表示锁的持有状态。
    • 如果键不存在,则设置成功,表示获取锁;否则失败。
    • 设置一个过期时间,防止死锁。
  2. 解锁

    • 使用 Lua 脚本确保删除操作的原子性。
    • 只有持有锁的客户端才能解锁。
  3. 续期

    • 如果任务执行时间较长,可以通过定时刷新锁的过期时间来防止锁提前释放。

代码实现

以下是一个基于 Java 和 Redis 的分布式锁实现,使用 Jedis 客户端库。

1. 加锁逻辑

java 复制代码
import redis.clients.jedis.Jedis;

import java.util.UUID;

public class RedisDistributedLock {
    private Jedis jedis;
    private String lockKey;
    private int expireTime; // 锁的过期时间(秒)
    private String lockValue; // 锁的唯一标识

    public RedisDistributedLock(Jedis jedis, String lockKey, int expireTime) {
        this.jedis = jedis;
        this.lockKey = lockKey;
        this.expireTime = expireTime;
        this.lockValue = UUID.randomUUID().toString(); // 唯一标识当前客户端
    }

    /**
     * 尝试获取锁
     *
     * @return 是否成功获取锁
     */
    public boolean acquireLock() {
        String result = jedis.set(lockKey, lockValue, "NX", "EX", expireTime);
        return "OK".equals(result);
    }

    /**
     * 释放锁
     */
    public void releaseLock() {
        String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                           "return redis.call('del', KEYS[1]) " +
                           "else return 0 end";
        jedis.eval(luaScript, 1, lockKey, lockValue);
    }

    /**
     * 续期锁
     */
    public void renewLock() {
        String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                           "return redis.call('expire', KEYS[1], ARGV[2]) " +
                           "else return 0 end";
        jedis.eval(luaScript, 1, lockKey, lockValue, String.valueOf(expireTime));
    }
}

2. 使用示例

java 复制代码
public class DistributedLockExample {
    public static void main(String[] args) {
        // 初始化 Redis 客户端
        Jedis jedis = new Jedis("localhost", 6379);

        // 创建分布式锁对象
        RedisDistributedLock lock = new RedisDistributedLock(jedis, "my_lock_key", 10);

        try {
            // 尝试获取锁
            if (lock.acquireLock()) {
                System.out.println("成功获取锁,执行业务逻辑...");
                Thread.sleep(5000); // 模拟业务逻辑处理

                // 续期锁
                lock.renewLock();
                System.out.println("锁已续期,继续执行业务逻辑...");
            } else {
                System.out.println("未能获取锁,等待...");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 释放锁
            lock.releaseLock();
            System.out.println("锁已释放");
        }

        // 关闭 Redis 连接
        jedis.close();
    }
}

UML 图

以下是分布式锁实现的 UML 类图和序列图。

1. 类图

2. 序列图


总结

通过 Redis 实现分布式锁是一种高效且可靠的方案,适用于分布式系统中的资源共享场景。我们通过 SETNX 和 Lua 脚本保证了锁的互斥性和安全性,同时通过设置过期时间和续期机制避免了死锁的发生。

希望本文对你有所帮助!如果你有任何问题,欢迎留言讨论。

相关推荐
YOU OU1 小时前
Redis基础常识与命令
数据库·redis·缓存
Database_Cool_3 小时前
OLTP 和 OLAP 区别详解:分析型数据库和事务型数据库怎么选(附阿里云 AnalyticDB MySQL 选型指南)
数据库·mysql·阿里云
爱写代码的阿森4 小时前
鸿蒙三方库 | harmony-utils之KvUtil键值型数据库操作详解
数据库·华为·harmonyos·鸿蒙·huawei
Database_Cool_4 小时前
单机 MySQL 迁移到分布式数据库方便吗?阿里云 PolarDB-X 100% MySQL 协议兼容零改造平滑迁移
数据库·分布式·mysql
姜太小白5 小时前
【MySQL】 索引优化实战:解决 WHERE 等值 + IS NULL 查询,TEXT 字段报错 1167 的完整指南
数据库·mysql
窝子面5 小时前
手搓最简前后端协作-node
javascript·数据库
吳所畏惧5 小时前
宝塔面板Redis密码修改指南:SSH命令修改 vs 面板UI界面修改,哪个更靠谱?
运维·服务器·数据库·redis·缓存·ssh
DFT计算杂谈6 小时前
无 Root 权限在 Tesla K80 零门槛部署 DeepSeek 大模型
linux·服务器·网络·数据库·机器学习
HPFBoy6 小时前
log4net 数据库存日志正确配置
数据库