【Redis】基于Redission实现分布式锁(代码实现)

目录

基于Redission实现分布式锁解决商品秒杀超卖的场景:

1.引入依赖:

2.加上redis的配置:

3.添加配置类:

4.编写代码实现:

5.模拟服务器分布式集群的情况:

        1.右键点击Copy Configuration

        2.点击Modify option

        3. 选择VM option(用于指定新的端口)

        4.输入想要指定的端口(比如):-Dserver.port=8082 点击Apply

        5.出现新的进程,点击启动,就可以进行分布式多节点测试。

使用Jmeter进行压测


        (单机部署)多线程高并发情况下对同一个共享资源进行读写时,会出现数据错乱(数据不一致)的问题;加锁(同步锁)可以解决出现数据不一致的问题;(其他线程进行等待持有锁的线程执行完成后才能进行正常的处理)。
        但是随着用户量日益增多,单个服务器压力越来越大,所以使用多个服务器进行分布式集群部署,虽然降低了服务器的压力,提高了服务器的吞吐量。但是还是会出现数据不一致的问题,这时候发现是是同步锁(synchronized)的问题,同步锁基于JVM的,他只能锁住单个服务器中一个线程,但是经过分布式集群部署过后,每台服务器在并发的情况下只能锁住一个线程,所以高并发情况下,还是会出现数据错乱的情况。(假如4个服务器,每台服务器都处于高并发的情况,然后同步锁只能锁住一个线程,这时候每个服务器锁住一个线程,最多可以出现4个线程同时对数据库进行操作,就会造成数据不一致的问题(例如常说的秒杀超卖的情况))

        经过查阅资料发现可以通过分布式锁可以解决,然后有三种主流的分布式锁的解决方案分别是使用基于Mysql/Zookeeper/redis实现分布式锁。由于我们系统使用到了Redis,考虑Zookeeper需要重新部署到服务器,避免间接增加服务器的成本,所以直接使用Redis来实现分布式锁。我们发现使用Redis的setNX可以很简单的实现分布式锁。
        那么setNX的特性是什么呢?
        当一个线程进来,往Redis当中通过setNX去存储一个值的时候,他会根据键值(key)去查看是否存在value值,没有就存储一个值返回true,有就返回一个false,注意一定要加上锁的过期时间,避免线程阻塞。(当用户在请求的过程当中,通过setNX进行加锁完成的时候,这个服务器挂掉了,当其他线程进行setNX进行上锁的时候,发现键当中一直会有值,造成了死锁,其他线程加锁不成功就会造成阻塞)。所以一定要加上过期时间。

        随着业务的扩展,又出现了一些问题,就是1.业务的处理时间超过了锁的过期时间和2.线程1可能释放了线程2所持有的锁,【线程1还没将业务处理完成就释放锁,导致线程2拿到锁处理自己的业务。当线程1执行完成后,释放了锁,但是此时线程2已经拿到了当前锁,所以线程1释放的是线程2的锁。】
        如何解决这些问题呢?
        1.加长锁的过期时间,并增加子线程每10秒去确认线程是否在线。在线则将过期时间重设(续命--他们所说的看门狗);
        2.给锁的值设置一个唯一ID(UUID)-(使用setNx进行尝试获取锁的时候,如果获取成功,将锁的值设置为一个唯一的ID,释放锁的时候会拿着key去获取锁的值是否与自己的唯一ID一致,一致才进行释放锁,从而就不会释放其他线程的锁)

        上述说这么多,如果让我们自己写起来确实有些麻烦,这时候查阅发现redis他本身已经提供了一个Redission的组件已经解决了这些问题。

那么下面我就提供一个

基于Redission实现分布式锁解决商品秒杀超卖的场景:

springboot版本:2.6.13

redission版本:3.22.0

1.引入依赖:

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

2.加上redis的配置:

server:port: 8083
spring:redis:host: 127.0.0.1password:port: 6379timeout: 1000

3.添加配置类:

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RedissonConfig {@Value("${spring.redis.host}")private String host;@Value("${spring.redis.port}")private String port;@Beanpublic RedissonClient getRedisson(){Config config = new Config();//单机模式  依次设置redis地址和密码config.useSingleServer().setAddress("redis://" + host + ":" + port).setTimeout(30000); // 设置缓存过期时间为30秒return Redisson.create(config);}
}

4.编写代码实现:


import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import java.util.Objects;@RestController
@RequestMapping("/redisLock")
public class RedisLockController {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Resourceprivate RedissonClient redisson;// 秒杀商品keyprivate static final String REDIS_KEY = "secKillProductKey:";private static final String LOCK_KEY = "secKillProduct";// 秒杀商品总个数private static final int PRODUCT_SIZE = 1000;/*** 初始化秒杀商品总个数到redis中* 注意:测试的时候,先调用这个接口初始化库存*/@GetMapping("/init")public void init() {// 初始化库存 将库存存到redis中stringRedisTemplate.opsForValue().set(REDIS_KEY, String.valueOf(PRODUCT_SIZE));}/*** 秒杀*/@GetMapping("/secKill")public void secKill() {// 获取锁RLock lock = redisson.getLock(LOCK_KEY);try {// 加锁lock.lock();int s = Integer.parseInt(Objects.requireNonNull(stringRedisTemplate.opsForValue().get(REDIS_KEY)));if (s > 0) {// 扣库存s--;System.out.printf("秒杀商品个数剩余:" + s + "\n");// 更新库存stringRedisTemplate.opsForValue().set(REDIS_KEY, String.valueOf(s));} else {System.out.println("活动太火爆了,商品已经被抢购一空了!");}} catch (Exception e) {System.out.println(Thread.currentThread().getName() + "异常:");e.printStackTrace();} finally {// 释放锁lock.unlock();}}
}

5.模拟服务器分布式集群的情况:

        同一个服务不同端口,同时运行两个相同的主程序。

在service中复制一个进程,指定不同端口

        1.右键点击Copy Configuration

        2.点击Modify option

        3. 选择VM option(用于指定新的端口)

        4.输入想要指定的端口(比如):-Dserver.port=8082 点击Apply

        5.出现新的进程,点击启动,就可以进行分布式多节点测试。

使用Jmeter进行压测

首先需要先调用一下初始化的接口:127.0.0.1:8082/redisLock/init或127.0.0.1:8083/redisLock/init

1.设置线程组

2.两个HTTP请求,请求不同的端口(8082、8083)进行测试高并发多线程的情况:

3.服务器打印结果

经过测试,一秒钟1000个线程同时请求秒杀接收并没有出现超卖的问题。  

拓展:

       Redis本身是一个CP(一致性和分区容错性)模式的数据库,它通过主从复制实现高可用性,当主节点挂掉时,从节点会自动进行选举,选出一个新的主节点继续提供服务。但是,在主节点挂掉之前,它可能还来不及将最新的数据同步到从节点,这时就会出现数据不一致的问题。

         如果redis采用主从模式进行部署,当往redis中通过setNX进行加锁的过程中,主节点挂了,主节点的数据并没有同步到从节点当中,这种怎么办?

        可以使用RedLock(红锁)解决,RedLock是一个分布式锁的实现,它可以通过访问多个Redis节点来实现更高的可用性和一致性。RedLock的工作原理是,在加锁时,向多个Redis节点发送请求,只有当所有节点都成功返回时,才认为加锁成功。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PS系统教程27

Photoshop与Camera Raw Camera本身是作为插件存在的&#xff0c;处理对象Raw格式&#xff08;高清格式的图片标准&#xff09; JPG是压缩格式 Camera是源数据包&#xff0c;无损高清数据包 通道 通道只有黑白灰三种颜色&#xff0c;图层类似于前台&#xff0c;通道就是后台…

免费领!系统学习上位机编程的流程与基础教程

上位机电气自动化plc编程全套入门教程工具 华山编程导师根据当前招聘需求的关键点&#xff0c;原创录制了一套系统的学习流程和基础教程&#xff0c;帮助你从快速入门到掌握上位机编程的技能。 二. 学习准备 为了更好地学习并实现80%以上的代码运行&#xff0c;建议准备一个工…

label studio数据标注平台的自动化标注使用

&#xff08;作者&#xff1a;陈玓玏&#xff09; 开源项目&#xff0c;欢迎star哦&#xff0c;https://github.com/tencentmusic/cube-studio 做图文音项目过程中&#xff0c;我们通常会需要进行数据标注。label studio是一个比较好上手的标注平台&#xff0c;可以直接搜…

SAP ABAP 之容器

文章目录 前言一、案例介绍/笔者需求二、自定义容器 a.实例化对象 b.自定义容器效果演示 c.Copy Code 三、自适应容器 a.常用 必须 参数理解 b.METRIC 度量单位 c.RATIO 百分比尺寸 d.STYLE 容器…

云计算基础知识

前言&#xff1a; 随着ICT技术的高速发展&#xff0c;企业架构对计算、存储、网络资源的需求更高&#xff0c;急需一种新的架构来承载业务&#xff0c;以获得持续&#xff0c;高速&#xff0c;高效的发展&#xff0c;云计算应运而生。 云计算背景 信息大爆炸时代&#xff1a…

小白学python(第二天)

哈喽&#xff0c;各位小伙伴们我们又见面了&#xff0c;昨天的文章吸收得如何&#xff1f;可有不懂否&#xff1f;如有不懂可以在品论区留言哦&#xff0c;废话不多说&#xff0c;开始今天的内容。 字符及字符串的续讲 字符&#xff1a;英文字母&#xff0c;阿拉伯数字&#x…

STM32学习-HAL库 串口通信

学完标准库之后&#xff0c;本来想学习freertos的&#xff0c;但是看了很多教程都是移植的HAL库程序&#xff0c;这里再学习一些HAL库的内容&#xff0c;有了基础这里直接学习主要的外设。 HAL库对于串口主要有两个结构体UART_InitTypeDef和UART_HandleTypeDef&#xff0c;前者…

VC++开发积累——vc++6.0中删除函数的方法,右键,Delete

目录 引出插曲&#xff1a;删除函数的方法多行注释的实现代码输入的自动提示搜索出来&#xff0c;标记和取消标记跳转到上一步的位置 ctrl TAB 总结其他规范和帮助文档创建第一个Qt程序对象树概念信号signal槽slot自定义信号和槽1.自定义信号2.自定义槽3.建立连接4.进行触发 自…

26.高级特性(上)

目录 一、不安全的Rust二、不安全的超能力2.1 概念2.2 解引用裸指针2.3 调用不安全的函数或方法2.3 创建不安全代码的安全抽象2.4 使用extern函数调用外部代码2.5 访问或修改可变静态变量2.6 实现不安全trait2.7 访问联合体中的字段 三、高级trait3.1 关联类型在trait定义中指定…

百元蓝牙耳机哪款好?值得购买的百元蓝牙耳机品牌有这些

在如今移动互联网时代&#xff0c;蓝牙耳机已经成为不少人生活中的必备产品。然而&#xff0c;市面上的蓝牙耳机种类繁多&#xff0c;价格也参差不齐&#xff0c;选择一款性价比高的产品成了不少消费者的难题。尤其是针对百元左右的蓝牙耳机&#xff0c;更是需要慎重选择。那么…

考研数学|张宇和武忠祥,强化能不能同时跟?

可以说你跟武老师学明白了&#xff0c;120完全没问题&#xff01;如果追求更高&#xff0c;宇哥的怀抱也想你敞开&#xff01; 学长我21年一战数学83&#xff0c;总分没过线&#xff0c;22年二战143&#xff0c;逆袭上岸211&#xff01;市面上的老师我基本都听过&#xff0c;最…

【vite】define 全局常量定义

&#x1f9ed; define 说明 类型&#xff1a; Record<string, any> 定义全局常量替换方式。其中每项在开发环境下会被定义在全局&#xff0c;而在构建时被静态替换。 Vite 使用 esbuild define 来进行替换&#xff0c;因此值的表达式必须是一个包含 JSON 可序列化值&a…

[MySql]两阶段提交

文章目录 什么是binlog使用binlog进行恢复的流程 什么是redolog缓冲池redologredolog结构 两阶段提交 什么是binlog binlog是二进制格式的文件&#xff0c;用于记录用户对数据库的修改&#xff0c;可以作用于主从复制过程中数据同步以及基于时间点的恢复&#xff08;PITR&…

Matlab|【防骗帖】考虑时空相关性的风电功率预测误差建模与分析

目录 1 主要内容 2 部分程序 3 下载链接 1 主要内容 这个程序《考虑时空相关性的风电功率预测误差建模与分析》画的图片非常漂亮&#xff0c;和原文献基本一致&#xff0c;但是实际上内容并未实现出来&#xff0c;主要就是利用现有的风电预测的数据和结果做了相关的图&#…

Verilog的逻辑系统及数据类型(一):四值逻辑系统

目录 1. Verilog采用的四值逻辑系统2.主要数据类型2.1 net&#xff08;线网&#xff09;2.2 寄存器类 &#xff08;register)2.3 Verilog中net和register声明语法2.3.1 net声明2.3.2 寄存器声明 2.4 选择正确的数据类型2.5 选择数据类型时常犯的错误2.5.1 信号类型确定方法总结…

目标检测数据集 - 手机屏幕表面表面缺陷检测数据集下载「包含VOC、COCO、YOLO三种格式」

数据集介绍&#xff1a;手机屏幕表面缺陷检测数据集&#xff0c;真实采集高质量手机屏幕表面含缺陷图片数据&#xff0c;数据集含多款不同型号和品牌的手机屏幕表面图片数据&#xff0c;包括苹果手机屏、三星手机屏、华为手机屏等数据。数据标注标签包括 Bubble 气泡/水滴、Scr…

现在的Java面试都这么扯淡了吗?

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「java的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“666”之后私信回复“666”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01;开发兼过半年面试官 刚开始…

upload-labs第14关

upload-labs第14关 第十四关一、源代码分析代码审计 二、绕过分析a. 制作图片码首先需要一个照片&#xff0c;然后其次需要一个eval.php。 b.上传图片码上传成功 c.结合文件包含漏洞进行访问访问&#xff1a;http://192.168.1.110/upload-labs-master/include.php?filehttp://…

VUE div的右上角的角标/标签

一、效果图 二、代码 <div class"comp-overview"><div class"overview-item" v-for"(item,index) in overviewInfoList" :key"index"><div class"angle_mark"><span>{{item.label}}</span>&…

重学java 73.设计模式

本想送你一本沉思录&#xff0c;可该迷途知返的人是我 —— 24.6.18 设计模式 设计模式(Design pattern)&#xff0c;是一套被反复使用、经过分类编目的、代码设计经验的总结&#xff0c;使用设计模式是为了可重用代码、保证代码可靠性、程序的重用性,稳定性。 1995 年&#x…