分布式锁的实现方式 - redis

场景:项目要从单实例变为多实例部署了,从而引入了一个问题,就是定时任务会多次执行(没一个实例都会执行一次)。为了解决这个问题,就要使用到分布式锁。

使用哪一种方式实现分布式锁

分布式锁的实现有多种:

  • 第一种:使用数据库,当要上锁时想数据库中添加一条数据,释放锁时删除数据即可。这种方式要维护一张存放锁状态的表。而且性能不好,不推荐使用。
  • 第二种:使用 zookeeper 来实现,zookeeper 是分布式协调服务,它的数据是以节点的方式存储,节点操作是原子性的。当我们要上锁时,添加一个临时节点,释放锁时删除这个节点。
  • 第三种:使用 redis 来实现。redis 中的 SETNX 命令是原子性的,命令可以尝试将一个指定的键设置为某个值,只有当该键不存在时才能设置成功。

因为我在项目中没有使用到 zookeeper ,所以不用为了实现分布式锁而去部署一套 zookeeper。 而数据库方式有性能问题,最终选择了使用 redis 方式实现。

创建 RedisDistributedLock 工具类

SpringBoot项目使用的 redisTemplate 来操作 redis,具体代码如下:

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;

@Component
public class RedisDistributedLock {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    public boolean lock(String lockKey, String lockValue, long expireTime) {
        return redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue,expireTime, TimeUnit.MILLISECONDS);
    }


    public void unLock(String lockKey, String lockValue) {
        String currentValue = redisTemplate.opsForValue().get(lockKey);
        if (currentValue != null && currentValue.equals(lockValue)) {
            String luaScript = "if redis.call('get', KEYS[1]) then return redis.call('del', KEYS[1]) else return 0 end";
            RedisScript<Long> redisScript = new DefaultRedisScript<>(luaScript, Long.class);
            redisTemplate.execute(redisScript, Collections.singletonList(lockKey));
        }
    }
}

lock 方法中的 lockKey 为锁的对象,lockValue 是为释放锁时会用到,防止释放了别人的锁,expireTime 是为了防止死锁。

unlock 方法中使用了 lua 脚本,确保正确的释放锁。

END

PS:欢迎大家关注我的公众号 小城边AI,直接搜索即可添加,可以体验AI问答,持续为大家推送相关优质技术文,共同进步,一起加油~

个人导航网站:小城边-个人导航 (gitee.io)

相关推荐
黄俊懿6 小时前
【架构师从入门到进阶】第六章:服务集群优化——第八节:线程数公式
java·服务器·数据库·分布式·性能优化·架构·系统架构
imDwAaY7 小时前
操作系统如何管理程序运行?从线程、进程到内存隔离与用户态切换:CS162 Note2
android·java·redis
大菠萝爱上小西瓜8 小时前
基于 Spark + Iceberg 湖仓一体的 Netflix 流媒体用户行为全链路数仓与 ALS 智能推荐决策系统(含穿透下钻大屏)
大数据·分布式·spark
码途行者9 小时前
处理超时未支付订单:两套轻量化方案,附 PHP 极简实现
开发语言·redis·php
吴建旭 智宅焕9 小时前
智能家居售后服务体系的架构设计:分布式售后风险的集中式兜底方案
分布式·智能家居
草莓熊Lotso13 小时前
【C++ 基于微服务的即时通讯系统】etcd + brpc 从安装到服务注册发现全链路实战
网络·数据库·c++·redis·微服务·etcd
lisanmengmeng19 小时前
Ganglia分布式集群监控系统安装手册
分布式
我不会起名字32220 小时前
Redis 突然只能读不能写:MISCONF 报错的 3 类触发条件与 4 步恢复
运维·redis·持久化·排查·misconf
我不会起名字32221 小时前
Redis 从 0 到 1(九):主库宕机 30 秒自动切主——1 主 2 从 3 哨兵 + Go 客户端
redis·docker·sentinel·高可用·哨兵
Smoothcloud润云1 天前
GPU算力平台推荐:新手租GPU时,镜像环境和显存应该怎么选?
大数据·人工智能·pytorch·分布式·深度学习·gpu算力