分布式锁 Redis+RedisSon

news2024/9/9 0:41:52

文章目录

    • 1.什么是分布式锁
    • 2.分布式锁应该具备哪些条件
    • 3.分布式锁主流的实现方案
    • 4.未添加分布式锁存在的问题
      • 4.1测试未添加分布式锁的代码
        • 通过jmeter发送请求
      • 4.2 添加线程同步锁
        • 集群部署
          • 配置nginx
        • 修改jmeter端口号
      • 4.3 使用redis的setnx命令实现分布式锁
        • 解决办法
      • 4.4 使用try、finally优化
      • 4.5 添加分布式锁的过期时间
      • 4.6 解决分布式锁命令的原子性问题
      • 4.7 把线程ID做为分布式锁的value
    • 5.使用redisson实现分布式锁
      • 5.1 添加 Redisson 依赖
      • 5.2 获取 Redisson 客户端实例
      • 5.3 获取分布式锁
      • 5.4 Redisson分布式锁的卖现原理图
    • 6 Redisson相关锁介绍
      • 6.1 可重入锁
      • 6.2 联锁概述
      • 6.3 RedLock

1.什么是分布式锁

问题描述: 随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式系统多线程、多进程且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的 JavaAPI 并不能提供分布式锁的能力,为了解决这个问题就需要一种跨IV的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题。

与分布式锁相对就的是单体结构中的锁 (单机锁) ,我们在写多线程程序时,避免同时操作一个共享变量产生数据问题,通常会使用一把锁来互斥以保证共享变量的正确性,其使用范围是在同一个JVM进程中。如果换做是不同机器上的MM进程,需要同时操作一个共享资源,如何互斥呢?现在的业务应用通常是微服务架构,这也意味着一个应用会部署多个进程,多个进程如果需要修改MySQL中的同一行记录,为了避免操作乱序导致脏数据,此时就需要引入分布式锁了。

2.分布式锁应该具备哪些条件

  • 在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行
  • 高可用的获取锁与释放锁
  • 高性能的获取锁与释放锁
  • 具备可重入特(可理解为重新进入,由多于一个任务并发使用,而不必担心数据错误)
  • 具备锁失效机制,即自动解锁,防止死锁
  • 具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败

在这里插入图片描述

3.分布式锁主流的实现方案

  • 1.基于缓存(redis等)
  • 2.基于zookeeper

每一种分布式锁解决方案都有各自的优缺点

  • 1.性能:redis最高
  • 2.可靠性:zookeeper最高

这里我们就基于redis实现分布式锁。

4.未添加分布式锁存在的问题

实现秒杀下单减库存案例:
创建springboot项目,导入redis依赖,在yml中进行redis的配置:
依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置:

spring:
  redis :
    database:0
    host:localhost
    port:6379

4.1测试未添加分布式锁的代码

操作redis

# 在redis 中设置一个stock等于10
set stock 0
get stock 

在这里插入图片描述

package cn.js;


import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;


@RestController
public class Indexcontroller {
   
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @RequestMapping("/deductstock")
    public String deductstock() {
   
        int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
        if (stock > 0) {
   
            int realstock = stock - 1;
            stringRedisTemplate.opsForValue().set("stock", realstock + "");
            System.out.println("扣减成功,剩余库存:" + realstock);
        } else {
   
            System.out.println("扣减失败,库存不足");
        }
        return "end";
    }
}


通过jmeter发送请求

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

通过命令再次查看redis

在这里插入图片描述

我们先清空redis再试一次

在这里插入图片描述

在这里插入图片描述

再次通过jmeter发送请求

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

两次结果

在这里插入图片描述

在这里插入图片描述

研究代码发现存在线程安全问题,接下来可以加个同步代码锁synchronized进行优化

4.2 添加线程同步锁

package cn.js;


import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;


@RestController
public class Indexcontroller {
   
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @RequestMapping("/deductstock")
    public String deductstock() {
   
        
        synchronized (this){
   
            int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
            if (stock > 0) {
   
                int realstock = stock - 1;
                stringRedisTemplate.opsForValue().set("stock", realstock + "");
                System.out.println("扣减成功,剩余库存:" + realstock);
            } else {
   
                System.out.println("扣减失败,库存不足");
            }
           
        }
	 return "end";
    }
}


在这里插入图片描述

在这里插入图片描述

目前我们的环境是单体服务,可以通过 synchronized JVM锁进行解决,但是如果是集群部署的话,synchronized锁是没有用的

集群部署
配置nginx
打开nginx中的nginx.conf文件

在这里插入图片描述

在.idea的workspace.xml中配置

<option name="configurationTypes">
<set>
<option value="springBootApplicationconfigurationType"/>
</set>
</option>
修改jmeter端口号

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

可以看到集群部署会出现超卖问题

重启IDEA

最后使用imeter工具,模拟高并发场景进行压力测试,查看控制台打印日志,发现还是出现库存量一样的数据,说明超卖问题还是存在。

分析得出:在分布式环境下synchronized是不起作用的,因为一个synchronized只在一个tomcat的iym进程内有效,在一个分布式系统,如何解决并发的资源争抢问题呢?

4.3 使用redis的setnx命令实现分布式锁

解决办法
可以通过redis的setnx命令的互斥性:

在这里插入图片描述

package cn.js;


import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【2025留学】德国留学真的很难毕业吗?为什么大家不来德国留学?

大家好&#xff01;我是德国Viviane&#xff0c;一句话讲自己的背景&#xff1a;本科211&#xff0c;硕士在德国读的电子信息工程。 之前网上一句热梗&#xff1a;“德国留学三年将是你人生五年中最难忘的七年。”确实&#xff0c;德国大学的宽进严出机制&#xff0c;延毕、休…

【日常设计案例分享】通道对账

今天跟同事们讨论一个通道对账需求的技术设计。鉴于公司业务线有好几个&#xff0c;为避免不久的将来各业务线都重复竖烟囱&#xff0c;因此&#xff0c;我们打算将通道对账做成系统通用服务&#xff0c;以降低各业务线的开发成本。 以下文稿&#xff08;草图&#xff09;&…

正点原子imx6ull-mini-Linux设备树下的LED驱动实验(4)

1&#xff1a;修改设备树文件 在根节点“/”下创建一个名为“alphaled”的子节点&#xff0c;打开 imx6ull-alientek-emmc.dts 文件&#xff0c; 在根节点“/”最后面输入如下所示内容 alphaled {#address-cells <1>;#size-cells <1>;compatible "atkalp…

昇思25天学习打卡营第1天|快速入门实操教程

昇思25天学习打卡营第1天|快速入门实操教程 目录 昇思25天学习打卡营第1天|快速入门实操教程 一、MindSpore内容简介 主要特点&#xff1a; MindSpore的组成部分&#xff1a; 二、入门实操步骤 1. 安装必要的依赖包 2. 下载并处理数据集 3. 构建网络模型 4. 训练模型…

WIN下的文件病毒

文件病毒 一.windows下知识句柄禁用某些警告MAX_PATH_WIN32_FIND_DATAWFindFirstFileW注册到服务代码&#xff08;自启动&#xff09;隐藏窗口 二.客户端代码三.服务端代码 一.windows下知识 句柄 相当于指针&#xff0c;用来表示windows下的一些对象&#xff1b; 禁用某些警…

vue3中使用ant-design-vue

ant-design-vue官网&#xff1a;Ant Design Vue — An enterprise-class UI components based on Ant Design and Vue.jsAn enterprise-class UI components based on Ant Design and Vuehttps://www.antdv.com/components/overview-cn/ 安装 npm i -S ant-design-vue 引入 …

前端实现【 批量任务调度管理器 】demo优化

一、前提介绍 我在前文实现过一个【批量任务调度管理器】的 demo&#xff0c;能实现简单的任务批量并发分组&#xff0c;过滤等操作。但是还有很多优化空间&#xff0c;所以查找一些优化的库&#xff0c; 主要想优化两个方面&#xff0c; 上篇提到的&#xff1a; 针对 3&…

“数说”巴黎奥运会上的“中国智造”成果

引言&#xff1a;随着“中国智造”在欧洲杯上方兴未艾&#xff0c;在巴黎奥运会上&#xff0c;中国智造继续以多种形式和领域展现了其强大的实力和创新能力。以格力公开表示将为巴黎奥运村提供345台格力空调&#xff0c;为中国制造的清凉送至巴黎事件拉开中国制造闪亮巴黎奥运会…

CTF Web SQL注入 10000字详解

这里写目录标题 涉及的数据库知识unionorder bydatabase()information_schemalimit--空格注释replaceinto outfilelikeGROUP BYHAVINGGROUP BY、HAVING、WHERE之间的关系regexp 原理信息收集操作系统数据库判断注入点注入点类型POST注入数字型注入字符型注入搜索型注入Insert/u…

Debian12 安装Docker 用 Docker Compose 部署WordPress

服务器准备&#xff1a; 以root账号登录&#xff0c;如果不是root&#xff0c;后面指令需要加sudo apt update apt install apt-transport-https ca-certificates curl gnupg lsb-release添加GPG密钥&#xff0c;推荐国内源 curl -fsSL https://mirrors.aliyun.com/docker…

ArchLinux部署waydroid

在Arch Linux系统上部署Waydroid运行Android APP 文章目录 在Arch Linux系统上部署Waydroid运行Android APP1. 安装要求2. 本机环境3. 安装 Waydroid4. 网络配置5.注册Google设备6. 运行效果图 Waydroid是Anbox配合Haliun技术开发的LXC Android容器&#xff0c;可在GUN/Linux系…

C语言中的指针基础

文章目录 &#x1f34a;自我介绍&#x1f34a;地址&#x1f34a;C语言中的指针 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以&#xff1a;点赞关注评论收藏&#xff08;一键四连&#xff09;哦~ &#x1f34a;自我介绍 Hello,大家好&#xff0c;我是小珑也要变强&am…

Spring Boot 3 + Resilience4j 简单入门 + Redis Cache 整合

1. 项目结构 2. Maven依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.1.2</version><relativePath/> <!-- lookup parent from repository --&…

CSRF Token 原理

CSRF 攻击 CSRF 攻击成功的关键是&#xff0c;恶意网站让浏览器自动发起一个请求&#xff0c;这个请求会自动携带 cookie &#xff0c;正常网站拿到 cookie 后会认为这是正常用户&#xff0c;就允许请求。 防范 如果在请求中加一个字段&#xff08;CSRF Token&#xff09;&am…

C++笔记之指针基础

函数重载:(C++特性) 定义: C++允许函数重名,但是参数列表要有区分 在相同的作用域定义同名的函数,但是它们的参数要有所区分,这样的多个函数构成重载关系 objdump -d test.exe >log.txt 将test.exe反汇编并将结果重定向到log.txt 文件中 ,然后在 log.txt中找到定…

学习网络安全 为什么Linux首择Kali Linux? 以及如何正确的使用Kali Linux

1.什么是kali linux&#xff1f; Kali Linux是一款基于Debian的Linux发行版&#xff0c;主要用于网络安全测试和渗透测试。它由全球顶尖的安全专家和黑客社区维护开发&#xff0c;提供了丰富的工具和资源&#xff0c;用于测试安全性、漏洞利用和渗透测试。此外&#xff0c;Kal…

MySQL 性能调优

文章目录 一. MySQL调优金字塔1. 架构调优2. MySQL调优3. 硬件和OS调优4. 小结 二. 查询性能调优三. 慢查询1. 概念2. 优化数据访问3. 请求了不需要数据&#xff0c;怎么做4. 是否在扫描额外的记录5. 慢查询相关配置 & 日志位置6. 小结 四. 查询优化器五. 实现调优手段 一.…

24、Python之面向对象:责任与自由,私有属性真的有必要吗

引言 前面我们进一步介绍了类定义中属性的使用&#xff0c;今天我们对中关于属性私有化的话题稍微展开聊一下&#xff0c;顺便稍微理解一下Python设计的相关理念。 访问级别 在其他编程语言中&#xff0c;比如Java&#xff0c;关于类中的属性和方法通过关键字定义明确的访问级…

1、仓颉工程基础操作 cjpm

文章目录 1. 仓颉工程创建方式2. cjpm2.1 init 初始化工程2.2 run 运行工程 1. 仓颉工程创建方式 使用 cangjie studio 通过cangjie studio 创建 使用vscode插件 通过 VSCode 命令面板创建仓颉工程通过可视化界面创建仓颉工程 cjpm 注&#xff1a;具体使用参考官方文档&#…

探索分布式光伏运维系统的组成 需要几步呢?

前言 随着光伏发电的不断发展&#xff0c;对于光伏发电监控系统的需求也日益迫切&#xff0c;“互联网”时代&#xff0c;“互联网”的理念已经转化为科技生产的动力&#xff0c;促进了产业的升级发展&#xff0c;本文结合“互联网”技术提出了一种针对分散光伏发电站运行数据…