云原生微服务之分布式锁框架 Redisson

🌹作者主页:青花锁 🌹简介:Java领域优质创作者🏆、Java微服务架构公号作者😄
🌹简历模板、学习资料、面试题库、技术互助

🌹文末获取联系方式 📝

在这里插入图片描述

系列专栏目录

[Java项目实战] 介绍Java组件安装、使用;手写框架等

[Aws服务器实战] Aws Linux服务器上操作nginx、git、JDK、Vue等

[Java微服务实战] Java 微服务实战,Spring Cloud Netflix套件、Spring Cloud Alibaba套件、Seata、gateway、shadingjdbc等实战操作

[Java基础篇] Java基础闲聊,已出HashMap、String、StringBuffer等源码分析,JVM分析,持续更新中

[Springboot篇] 从创建Springboot项目,到加载数据库、静态资源、输出RestFul接口、跨越问题解决到统一返回、全局异常处理、Swagger文档

[Spring MVC篇] 从创建Spring MVC项目,到加载数据库、静态资源、输出RestFul接口、跨越问题解决到统一返回

[华为云服务器实战] 华为云Linux服务器上操作nginx、git、JDK、Vue等,以及使用宝塔运维操作添加Html网页、部署Springboot项目/Vue项目等

[Java爬虫] 通过Java+Selenium+GoogleWebDriver 模拟真人网页操作爬取花瓣网图片、bing搜索图片等

[Vue实战] 讲解Vue3的安装、环境配置,基本语法、循环语句、生命周期、路由设置、组件、axios交互、Element-ui的使用等

[Spring] 讲解Spring(Bean)概念、IOC、AOP、集成jdbcTemplate/redis/事务等


系列文章目录

第一章 Java线程池技术应用
第二章 CountDownLatch和Semaphone的应用
第三章 Spring Cloud 简介
第四章 Spring Cloud Netflix 之 Eureka
第五章 Spring Cloud Netflix 之 Ribbon
第六章 Spring Cloud 之 OpenFeign
第七章 Spring Cloud 之 GateWay
第八章 Spring Cloud Netflix 之 Hystrix
第九章 代码管理gitlab 使用
第十章 SpringCloud Alibaba 之 Nacos discovery
第十一章 SpringCloud Alibaba 之 Nacos Config
第十二章 Spring Cloud Alibaba 之 Sentinel
第十三章 JWT
第十四章 RabbitMQ应用
第十五章 RabbitMQ 延迟队列
Java锁的分类
分布式锁框架-Redisson


前言

Redisson 在基于 NIO 的 Netty 框架上,充分的利⽤了 Redis 键值数据库提供的⼀系列优势,在Java 实⽤⼯具包中常⽤接⼝的基础上,为使⽤者提供了⼀系列具有分布式特性的常⽤⼯具类。使得原本作为协调单机多线程并发程序的⼯具包获得了协调分布式多机多线程并发系统的能⼒,⼤⼤降低了设计和研发⼤规模分布式系统的难度。同时结合各富特⾊的分布式服务,更进⼀步简化了分布式环境中程序相互之间的协作。

1、redisson工作原理

在这里插入图片描述

2、看门狗原理

A服务先运行,在运行B服务,还没释放A的锁,A就挂了,会不会死锁呢?
答:没有导致死锁,因为底层有看门狗机制
默认指定锁时间为30s(看门狗时间)
锁的自动续期:若是业务超长,运行期间自动给锁上新的 30s,不用担心业务时间过长,锁就自动过期
加锁的业务只要运行完成,就不会给当前锁续期,及时不手动解锁,锁默认在30s 后自动删除。

3、spring boot与redisson的整合

3.1、添加库存服务:

stock-service

3.2、添加依赖

Maven

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
   <!-- <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        <version>2021.0.4.0</version>
    </dependency>-->
    <dependency>
        <groupId>org.redisson</groupId>
        <artifactId>redisson</artifactId>
        <version>3.19.1</version>
    </dependency>

Gradle

ext {
  //set('redissonVersion', "3.19.1") 
  redissonVersion = "3.19.1"
}
dependencies {
  implementation('org.springframework.boot:spring-boot-starter-web') {
    exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
  }
  implementation("org.redisson:redisson:${redissonVersion}")
  testImplementation('org.springframework.boot:spring-boot-starter-test')
  
}

3.3、添加配置

3.3.1、单机

redisson:
  addr:
    singleAddr:
      host: redis://localhost:6379
      password: 123456
      database: 0
      pool-size: 10

3.3.2、集群

redisson:
  addr:
    cluster:
      hosts: redis://47.96.11.185: 6370,...,redis://47.96.11.185:6373
      password : 123456

3.3.3、主从

redisson:
  addr:
    masterAndSlave:
      masterhost: redis : //47.96.11.185 : 6370
      slavehosts: redis://47.96.11.185: 6371,redis://47.96.11.185:6372
      password : 123456
      database : 0

3.4、配置RedissonClient

3.4.1、单机

/**
 * 配置RedissonClient
 */
@Configuration
public class RedissonConfig {
    @Value("${redisson.addr.singleAddr.host}")
    private String host;
    @Value("${redisson.addr.singleAddr.password}")
    private String password;
    @Value("${redisson.addr.singleAddr.database}")
    private int database;
    @Value("${redisson.addr.singleAddr.pool-size}")
    private int poolSize;
    @Bean
    public RedissonClient redissonClient(){
        Config config = new Config();
        config.useSingleServer().setAddress(host)
                .setPassword(password)
                .setDatabase(database)
                .setConnectionPoolSize(poolSize)
                .setConnectionMinimumIdleSize(poolSize);
        return Redisson.create(config);
    }
}

3.4.2、集群

/**
 * 配置RedissonClient
 */
@Configuration
public class RedissonConfig {
    @Value("${redisson.addr.cluster.hosts}")
    private String hosts;
    @Value("${redisson.addr.cluster.password}")
    private String password;

    /**
     * 集群模式
     *
     * @return
     */
    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useClusterServers().addNodeAddress(hosts.split("[,]"))
                .setPassword(password)
                .setScanInterval(2000)
                .setMasterConnectionPoolSize(10000)
                .setSlaveConnectionPoolSize(10000);
        return Redisson.create(config);
    }
}

3.4.3、集群

/**
 * 配置RedissonClient
 */
@Configuration
public class RedissonConfig {
    @Value("${redisson.addr.masterAndSlave.masterhost}")
    private String masterhost;
    @Value("${redisson.addr.masterAndSlave.slavehosts}")
    private String slavehosts;
    @Value("${redisson.addr.masterAndSlave.password}")
    private String password;
    @Value("${redisson.addr.masterAndSlave.database}")
    private int database;

    /**
     * 主从模式
     *
     * @return
     */
    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useMasterSlaveServers()
                .setMasterAddress(masterhost)
                .addSlaveAddress(slavehosts.split("[,]"))
                .setPassword(password)
                .setDatabase(database)
                .setMasterConnectionPoolSize(10000)
                .setSlaveConnectionPoolSize(10000);
        return Redisson.create(config);
    }
}

3.5、Redisson的使用

  • 获取锁 —— 公平锁和⾮公平锁
    // 获取公平锁
    RLock lock = redissonClient . getFairLock ( skuId );
    // 获取⾮公平锁
    RLock lock = redissonClient . getLock ( skuId );
  • 加锁 —— 阻塞锁和⾮阻塞锁
    // 阻塞锁(如果加锁成功之后,超时时间为 30s ;加锁成功开启看⻔狗,剩 5s 延⻓过期时间)
    lock . lock ();
    // 阻塞锁(如果加锁成功之后,设置⾃定义 20s 的超时时间)
    lock . lock ( 20 , TimeUnit . SECONDS );
    // ⾮阻塞锁(设置等待时间为 3s ;如果加锁成功默认超时间为 30s )
    boolean b = lock . tryLock ( 3 , TimeUnit . SECONDS );
    // ⾮阻塞锁(设置等待时间为 3s ;如果加锁成功设置⾃定义超时间为 20s )
    boolean b = lock . tryLock ( 3 , 20 , TimeUnit . SECONDS );
  • 释放锁
    lock . unlock ();
  • 应⽤示例
    // 公平⾮阻塞锁
    RLock lock = redissonClient . getFairLock ( skuId );
    boolean b = lock . tryLock ( 3 , 20 , TimeUnit . SECONDS );
  • 减库存加锁案例

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/stock")
public class StockController {
    @Autowired
    private RedissonClient redissonClient;
    @GetMapping("/reduceStock")
    public void reduceStock(@RequestParam String productId){
        // 获取⾮公平锁
        RLock lock = this.redissonClient.getLock("stock:" + productId);
        // 阻塞锁(如果加锁成功之后,设置⾃定义 20s 的超时时间)
        lock.lock(30, TimeUnit.SECONDS);
        System.out.println("加锁成功." + Thread.currentThread().getName());

        try {
            TimeUnit.SECONDS.sleep(25);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            System.out.println("解锁成功." + Thread.currentThread().getName());
            lock.unlock();
        }

    }
}

测试:浏览器发起两次两次减库存
http://localhost:8099/stock/reduceStock?productId=001

3.6、aop实现分布式锁

3.6.1、定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DistributeLock {
    /**
     * 参数下标
     * @return
     */
    int[] lockIndex() default {-1} ;

    /**
     * 锁的等待时间
     * @return
     */
    long waitTime() default 3000;

    /**
     * 时间单位
     * @return
     */
    TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
}

3.6.2、定义切面

/**
 * 定义分布式锁的切面
 */
@Component
@Aspect
public class DistributeLockAspect {
    @Autowired
    private RedissonClient redissonClient;

    @Around(value = "@annotation(lock)")
    public void distibuteLock(ProceedingJoinPoint proceedingJoinPoint, DistributeLock lock){
        Signature signature = proceedingJoinPoint.getSignature();
        StringBuilder stringBuilder = new StringBuilder();
        //方法所属的类
        String declaringTypeName = signature.getDeclaringTypeName();
        String name = signature.getName();

        stringBuilder.append(declaringTypeName);
        stringBuilder.append(name);

        //获取调用方法的参数
        Object[] args = proceedingJoinPoint.getArgs();

        int[] ints = lock.lockIndex();

        if(args != null) {
            final int length = args.length;
            if (length >0) {
                //考虑下标越界
                for (int anInt : ints) {
                    //把合法下标值放到sb
                    if (anInt >= 0 && anInt < length){
                        stringBuilder.append(JSON.toJSONString(args[anInt]));
                    }
                }
            }
        }

        //将方法的信息转成md5,作为锁的标识
        String key = SecureUtil.md5(stringBuilder.toString());


        //获取锁
        RLock rLock = redissonClient.getLock(key);
        //从注解获取时间单位
        TimeUnit timeUnit = lock.timeUnit();
        //从注解等待时间
        long waitTime = lock.waitTime();

        //执行业务代码
        try {
            //加锁
            rLock.tryLock(waitTime,timeUnit);
            System.out.println("成功加锁。" + Thread.currentThread().getName());
            proceedingJoinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }finally {
            //解锁
            rLock.unlock();
            System.out.println("成功解锁。" + Thread.currentThread().getName());
        }
    }
}

注解的使用:

@DistributeLock(lockIndex = {0,1},waitTime = 3,timeUnit = TimeUnit.SECONDS)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/322482.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

动物多指标生理监测:ZL-019A大小鼠饮食饮水监测系统

ZL-019A大小鼠饮食饮水监测系统是一款能够实时监测和分析动物的饮食、饮水、站立、活动量和活动轨迹等行为和代谢过程的智能系统。 本系统旨在定期测量实验动物的饮食饮水摄入行为&#xff0c;用户可根据需要自定义测量时间。通过定期测量&#xff0c;研究者无需再费心记录单个…

代码随想录 Leetcode454. 四数相加 II

题目&#xff1a; 代码 (首刷看解析 2024年1月15日&#xff09;&#xff1a; class Solution { public:int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {int n nums1.size();u…

【干货】数字化工厂常见术语合集

本文将为大家介绍一些行业通俗名称&#xff0c;希望对于从事“数字工厂”行业的朋友以及正在求职的朋友们有所助益。 数字化工厂&#xff08;"Digital factory"&#xff0c;简写为"DF"&#xff09;&#xff1a;是指利用先进的信息技术和数字化解决方案&am…

关于如何禁用、暂停或退出OneDrive等操作,看这篇文件就够了

​想知道如何禁用OneDrive?你可以暂停OneDrive的文件同步,退出应用程序,阻止它在启动时打开,或者永远从你的机器上删除该应用程序。我们将向你展示如何在Windows计算机上完成所有这些操作。 如何在Windows上关闭OneDrive 有多种方法可以防止OneDrive在你的电脑上妨碍你。…

AI自动写文章的软件有哪些?分享五款实用的

据相关数据统计&#xff0c;AI自动写文章的软件逐渐成为了现实。这些写作软件利用强大的自然语言处理和机器学习算法&#xff0c;能够自动生成文章&#xff0c;为写作工作提供了极大的便利。在本文中&#xff0c;我将向大家介绍五款实用的AI自动写文章的软件&#xff0c;一起来…

打破效率瓶颈:运用Excel提升文秘与行政工作质量

文章目录 一、数据整理二、数据分析三、报表制作四、图表展示五、模板应用六、宏编程七、安全与隐私《Excel高效办公&#xff1a;文秘与行政办公&#xff08;AI版&#xff09;》编辑推荐内容简介作者简介目录获取方式 在现代企业中&#xff0c;文秘与行政办公人员的工作内容繁杂…

文件批量重命名:如何给文件自定义名称,大量文件重命名的方法

在日常生活和工作中&#xff0c;经常要处理大量的文件&#xff0c;例如把文件重命名。手动重命名每个文件不仅耗时&#xff0c;而且容易出错。现在一起来看云炫文件管理器如何按自定义名称批量给文件重命名的技巧。 文件名自定义名称前后缩略图对比。 用自定义名称批量重命名…

Unity 编辑器篇|(五)编辑器拓展GUILayout类 (全面总结 | 建议收藏)

目录 1. 前言2. 参数3. 功能3.1 按钮&#xff1a;Button、RepeatButton3.2 文本&#xff1a;Label、TextArea、TextField、PasswordField3.3 工具栏&#xff1a;Toolbar3.4 切换框&#xff1a;Toggle3.5 滚动条&#xff1a;HorizontalScroll 、VerticalScroll3.6 滑条&#xff…

优思学院|质量管理五大工具和七大手法要点总结|2024

在现代企业管理中&#xff0c;质量管理是核心竞争力的重要组成部分。它不仅关系到产品的品质&#xff0c;更直接影响到企业的市场信誉和经济效益。本文将深入探讨质量管理中的五大工具及七大手法&#xff0c;这些工具和手法都贯穿了六西格玛DMAIC五步的方法论之中&#xff0c;是…

MYSQL第三次作业--单表查询

第三次作业 一、创建worker表 mysql> create table worker(-> 部门号 int(11) not null,-> 职工号 int(11) not null,-> 工作时间 date not null,-> 工资 float(8,2) not null,-> 政治面貌 varchar(10) not null default群众,-> 姓名 varchar(20) not n…

arrow,一个神奇的 Python 库!

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个神奇的 Python 库 - arrow。 Github地址&#xff1a;https://github.com/arrow-py/arrow 日期和时间处理是许多应用程序中的常见任务&#xff0c;但在 Python 中&#xf…

聚类算法之Kmeans聚类详解

聚类算法是无监督学习算法&#xff0c;它根据样本之间的相似性&#xff0c;将样本划分到不同的类别中&#xff1b;不同的相似度计算方法&#xff0c;会得到不同的聚类结果&#xff0c;常用的相似度计算方法有欧氏距离法。聚类算法的目的是在没有先验知识的情况下&#xff0c;自…

亚马逊卖家必备神器:鲲鹏系统助力产品排名飙升

亚马逊鲲鹏系统是一款功能强大的工具&#xff0c;为亚马逊卖家提供了多种实用功能&#xff0c;旨在提高产品排名、增加自然流量&#xff0c;并模拟真实的人类操作&#xff0c;以规避亚马逊的检测系统。 下面是亚马逊鲲鹏系统的主要功能和8大特点&#xff1a; 主要功能&#xf…

MATLAB对话框与菜单设计实验

本文MATLAB源码&#xff0c;下载后直接打开运行即可[点击跳转下载]-附实验报告https://download.csdn.net/download/Coin_Collecter/88740733 一、实验目的 1.掌握建立控件对象的方法。 2.掌握对话框设计方法。 3.掌握菜单设计方法。 二、实验内容 建立如下图所示的菜单。菜单…

(2023版)斯坦福CS231n学习笔记:DL与CV教程 (2) | 图像分类与损失函数

前言 &#x1f4da; 笔记专栏&#xff1a;斯坦福CS231N&#xff1a;面向视觉识别的卷积神经网络&#xff08;23&#xff09;&#x1f517; 课程链接&#xff1a;https://www.bilibili.com/video/BV1xV411R7i5&#x1f4bb; CS231n: 深度学习计算机视觉&#xff08;2017&#xf…

从第一性原理看大模型Agent技术

本文由下面的内部分享视频文字稿重新整理而成 从第一性原理看大模型Agent技术 引 一个乐观主义者的悲观估计 随着大规模模型技术的兴起&#xff0c;我们正处于一个崭新的智能时代的黎明。我们有一个大胆的预测&#xff0c;未来的5到10年将可能带来一场大变局&#xff1a;99%的…

Java异常:toString()和getMessage()区别

首先写了两个错误 Controller public class DemoController {RequestMapping("/show1")public String showInfo(){String str null;str.length();return "index";}RequestMapping("/show2")public String showInfo2(){int a 10/0;return &quo…

java多线程(并发)夯实之路-synchronized锁升级深入浅出

轻量级锁 使用场景&#xff1a;一个对象有多线程访问&#xff0c;但时间是错开的&#xff08;如果多线程同时访问&#xff0c;也就是有竞争的&#xff0c;会升级为重量级锁&#xff09; 轻量级锁对使用者是透明的&#xff0c;语法仍是synchronized 例&#xff1a; 以上的代码…

天津Java开发培训哪家好?选Java培训班要考虑

在当今社会&#xff0c;Java语言在软件开发领域具有举足轻重的地位&#xff0c;Java是一门面向对象编程语言&#xff0c;Java语言集合了C的优点&#xff0c;丢弃了缺点&#xff0c;所以Java语言表现的功能强大而简单易用&#xff0c;已经得到越来越多的应届毕业生和职场新人的认…

智慧公厕创造智能、整洁、舒适环境,让“方便”更方便

在现代城市建设中&#xff0c;智慧公厕已成为一项热点技术。通过物联感知、云管理数据处理和人性化智能设备的融合&#xff0c;智慧公厕让我们的“方便”变得更加方便。不仅实时感知和监控公共厕所的情况&#xff0c;还提升管理效率&#xff0c;为市民提供更人性化的服务。智慧…