Redis|springboot 使用 redis 做分布式锁

本贴最后更新于 1807 天前,其中的信息可能已经时异事殊

javaDEMO

Java 基础 Demo 站: https://www.javastudy.cloud
Java 中高级开发博客: https://www.lixiang.red
Java 学习公众号: java 技术大本营
java_subscribe

分布式锁总述

如果我们应用 A 部署了两台,然后这两台都为数据 D 做了缓存, 在某一时刻,两个机器都发现缓存失效了,这时候是两台机器都去请求数据库吗? 肯定不是,只能有一台机器去请求, 这时候分布式锁就派上用场了.
网上有很多网址都有提及到,分布式锁主要有三种实现方式,其本质核心就是先找到一个中间层,在中间层来决定哪个机器去访问
一. 在 Redis 中去创建同一个 key
二.在 Zookeeper 中去创建同一个 Node
三.在 Mysql 中创建一个唯一索引的数据行
本 DEMO 主要是介绍使用 Redis 去做分布式锁

Redis 做分布式锁

如上段所述,redis 做分面式锁主要是在 Redis 中去创建同一个 key,因此还是 set 命令的变形,set 命令参考文档:
https://redis.io/commands/set
网上大都是 setnx,但从文档中,我们可以看到,从 redis 2.6.12 之后,官方推荐直接使用 set 命令来实现

Starting with Redis 2.6.12 SET supports a set of options that modify its behavior:

  • EX seconds -- Set the specified expire time, in seconds.
  • PX milliseconds -- Set the specified expire time, in milliseconds.
  • NX -- Only set the key if it does not already exist.
    Note: Since the SET command options can replace SETNX, SETEX, PSETEX, it is possible that in future versions of Redis these three commands will be deprecated and finally removed.

如上,redis 中分布式锁可用 set lock:javastudy 1 ex 3 nx 来操作,如成功,则执行逻辑,然后删掉锁,或执行逻辑中有问题,则等锁自动过期

springboot 中使用 Redis 做分布式锁

首先是在 springboot 中使用 redis,参考文章:https://www.javastudy.cloud/articles/2019/11/04/1572845689729.html

DEMO 级别的

通过 RedisTemplate 实现上述 set 命令的 DEMO 代码如下:

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public boolean setNx(String key, Object value, long timeout) {
        return redisTemplate.opsForValue().setIfAbsent(key, value, timeout, TimeUnit.SECONDS);
    }

进阶的

做为 DEMO 级别,以上代码以够用,但是在生产中,如应用 A 先获取到了锁,但是锁了 10 秒,自己又在处理的过程中出了问题,没能删掉锁, 那后面的应用就 G 了,所以后面的应用 B 在没有获取到锁的时候,要先获取下这个 key 的创建时间,如果和当前时间的差别太大,B 就强制删掉这个锁
参考代码如下:

private boolean getLock(String lockKey,long expire, int count) {
        
        if (redisService.setNx(lockKey, DateUtils.currentTimeMillis(), expire)) {
            return true;
        } else {
            // 获取锁的创建时间
            long createTime = (long) redisService.get(lockKey);
	  // 这里的比较可以在expire基础上乘一个自定义的小数
            if ((DateUtils.currentTimeMillis() - createTime) > (expire)) {
                count++;
	        // 最大尝试次数
                if (count > MAX_RETRY_COUNT) {
                    return false;
                }
                redisService.del(lockKey);
		// 使用递归再尝试去获取锁
                getLock(lockKey,expire, count);
            }
            return false;
        }
    }

DEMO 总评

分布式锁,redis 做分布式锁这一块在面试中几乎是必问,不仅仅要做到对原理了解,更要写法熟练,本 DEMO 代码的工具方法可以直接拷贝使用,其中一些可扩展的点可以自行配置,更多的还是要根据业务场景来做选择技术方案,加油!

  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    286 引用 • 248 回帖 • 44 关注
  • 分布式
    80 引用 • 149 回帖 • 4 关注
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    943 引用 • 1460 回帖 • 3 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...