当前位置: 首页 > news >正文

【Redis】基于Redis实现秒杀功能

        业务的流程大概就是,先判断优惠卷是否过期,然后判断是否有库存,最好进行扣减库存,加入全局唯一id,然后生成订单。

一、超卖问题 

        真是的场景下可能会有超卖问题,比如开200个线程进行抢购,抢100个商品,最后发现生产力109个订单,库存发现是-9,这就出现了超卖问题。

        这个是怎么出现的呢?比如我现在判断库存为1那么我开始扣减库存,此时还没扣减的时候,线程二来,发现库存还是大于0,那么我线程2也开始扣减库存,此时线程一和线程二都执行扣减,就导致库存从1变为-1

        有两种解决方案,悲观锁和乐观锁,悲观锁就是用lock 或者 synchronized,让所有线程变成串行方式执行,乐观锁是判断之前查到的数据是否被修改了,如果被修改了就不允许下一步操作,重新获取最新的数据进行操作。

        乐观锁:版本号法设置版本号,每次进行减库存的时候都要进行版本+1。大概流程是这样的,先进行查询,版本号=1,库存=1,然后线程二进来了同样查询库存=1,版本号=1,然后线程1开始判断版本号是否等于之前查出来的版本号1,如果相等就更新并且版本+1。然后线程二在进行判断此时判断版本号与自己线程当前查出的版本号不一致1≠2了,此时更新失败。

        简化玩法,通过数据业务本身进行判断原本数据是否有变化,例如查出库存然后扣减库存的时候如果发现库存与查出的库存不一致,说明期间有线程将库存修改,那么就修改失败。 

二、一人一单问题

        同一个优惠卷,一个只能抢一次。在多线程情况下可能会出现一个人强好几次,都抢到了的情况。这和之前超卖问题差不多,都是第一次检查自己有没有抢购这个优惠卷的时候判断认为自己没有抢过,此时其他线程进来也查数据库也没有,所以会同时新增优惠卷抢购订单。但由于之前的超卖是修改的问题,而这个是新增的问题,所以不太好用乐观锁。

        可以用悲观锁,先获取用户的id,根据用户id获取锁提交事务然后释放锁,因为不同用户可以同时操作 ,但是同一个用户只能串行执行避免并发问题。

三、集群模式下一人一单问题

        对于多集群下,服务器有多个,可能用户会访问不同的服务器,假如在抢优惠卷的时候,分别发送了两个请求访问,然后分别发送请求到两台服务器,那么每台服务器的Tomcat不同,jvm也就不同,那么他们获取的锁对象也是不同的,所以同一个用户在这种情况下用synchronized是锁不住的。

        解决方案使用分布式锁

      分布式锁

        必须满足在多集群多线程下,多进程可见,并且互斥。mysql性能一般,安全性可以,高可用还可以,可以理由x锁锁住某条数据进行作为全局锁,然后通过报异常回滚释放锁。然后用redis的话,效率高,高可用,可以拓展主从机制,使用SETNX完成互斥。

        使用redis方式来实现分布式锁。

        代码实现

          setIfAbsent就相当于NX,然后时间是EX设置超时时间目的是为了宕机或者卡主,锁不释放的情况。

        锁的误删问题

        线程1在业务过程中卡住了,对应的锁因为时间太长锁失效了删除了,此时业务二进来获取锁,那么获取成功,在正常业务过程中业务一恢复正常,然后快结束的时候将锁释放,此时会把业务二中拿到的锁给释放掉。

        解决方法就是在获取锁的时候要存入线程id,释放锁的时候判断锁的线程id是不是自己的,是自己的才能释放,确保锁不会误删。 

        但是极端的情况下还会有锁的误删问题,比如在业务获取锁执行完毕之后,在进行判断是否是自己当前线程的锁,如果是那么此时突然阻塞,等下一个线程进行业务过程中获取锁,然后执行一般的时候线程一恢复正常他会进行释放锁,因为在阻塞之前进行过判断是否是当前线程,此时只执行释放锁的操作,那么依然会将就锁删除掉。

        解决方法

        要保证 判断是否是当前锁已经释放锁的过程是原子性的,要一块进行操作。我们可以用lua脚本,在里面执行redis的操作要么都执行成功要么都失败。

        在以上这些锁有一个问题,就是不可重入,不可重试,超时释放,主从一致性(用主节点加了一个锁,但是主从未同步完成的时候主节点挂了,那么此时其他线程又要获取锁发现从节点没有锁标志那么就会出现同一把锁获取两次不同线程的问题)。

        使用Redisson解决

                Redisson实现可重入锁原理

                是一个hash结构,key是锁的名字,对应的键值对的key是锁的线程的id,value是锁的使用次数,如果不存在就正常加锁,默认是value的value是1,所以如果解锁就将这个值-1,判断为0就释放锁,如果是重入的话,会判断这个锁是不是当前线程的如果是的话就会将锁的value的value+1,直到将锁逐层释放等到value的value为0时才释放。这些操作实际上是写在lua脚本里,保证原子性。

                Redisson实现锁的可重试,超时效

                首先会获取锁,判断锁是否存在,如果不存在就获取成功,如果手动设置了超时时间就直接结束。如果没有设置超时时间,看门狗会一直重复续约超时时间,默认是30秒然后30/3每隔10秒续约10秒,一直往目的是防止业务还没完成就自动释放锁。然后当时判断锁存在,那么会判断锁的时间还有吗,没有的话直接结束,如果有的话会有信号量机制订阅信息,等待锁的释放,如果收到锁释放的信息,那么它会再次判断是否超时,如果超时了结束,如果没超时重新获取一遍锁。如果锁释放成功会取消看门狗,因为业务结束会释放锁,所以意味着业务结束。

        Redisson实现锁的主从一致性。

        它实现的方法就是比如有三个节点,每次加锁必须将三个节点都加上锁,才叫获取锁成功,以此为依据。假设这三个节点有对应的从节点,假设其中有一个主节点崩溃,从节点作为主节点,此时如果主从没有及时更新,那么从节点作为主节点发现没有锁的表示,而其他两个阶段是正常的有锁的表示,此时如果有个线程趁虚而入,想获取锁此时只有第一个节点能获取锁,其他两个节点由于之前加了锁了,所以不能获取到锁,所以加锁失败。

相关文章:

【Redis】基于Redis实现秒杀功能

业务的流程大概就是,先判断优惠卷是否过期,然后判断是否有库存,最好进行扣减库存,加入全局唯一id,然后生成订单。 一、超卖问题 真是的场景下可能会有超卖问题,比如开200个线程进行抢购,抢100个…...

Hadoop 使用过程中 15 个常见问题的详细描述、解决方案

目录 问题 1:配置文件路径错误问题描述解决方案Python 实现 问题 2:YARN 资源配置不足问题描述解决方案Python 实现 问题 3:DataNode 无法启动问题描述解决方案Python 实现 问题 4:NameNode 格式化失败问题描述解决方案Python 实现…...

【Flutter 问题系列第 84 篇】如何清除指定网络图片的缓存

这是【Flutter 问题系列第 84 篇】,如果觉得有用的话,欢迎关注专栏。 博文当前所用 Flutter SDK:3.24.3、Dart SDK:3.5.3,网络图片缓存用的插件 cached_network_image: 3.4.1,缓存的网络图像的存储和检索用…...

【UE5】使用基元数据对材质传参,从而避免新建材质实例

在项目中,经常会遇到这样的需求:多个模型(例如 100 个)使用相同的材质,但每个模型需要不同的参数设置,比如不同的颜色或随机种子等。 在这种情况下,创建 100 个实例材质不是最佳选择。正确的做…...

鸿蒙动画开发07——粒子动画

1、概 述 粒子动画是在一定范围内随机生成的大量粒子产生运动而组成的动画。 动画元素是一个个粒子,这些粒子可以是圆点、图片。我们可以通过对粒子在颜色、透明度、大小、速度、加速度、自旋角度等维度变化做动画,来营造一种氛围感,比如下…...

IDEA2023 创建SpringBoot项目(一)

一、Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。 二、快速开发 1.打开IDEA选择 File->New->Project 2、…...

VSCode:终端打开一片空白,无cmd

第一步:找到右下角设置图标 第二步:找到 Terminal - Integrated - Default Profile: Windows: 选择一个本地存在的命令方式,重启即可 也可以直接在右下角直接选择...

Zea maize GO

1.涉及到新旧基因组的转化 B73v4_to_B73v5 (davidbioinformatics只支持新版基因组) MaizeGDB Map文件下载https://download.maizegdb.org/Pan-genes/B73_gene_xref/小处理脚本(制作map文件) import pandas as pd# 读取CSV文件 …...

Android开发实战班 - 数据持久化 - 数据加密与安全

在 Android 应用开发中,数据安全至关重要,尤其是在处理敏感信息(如用户密码、支付信息、个人隐私数据等)时。数据加密是保护数据安全的重要手段,可以有效防止数据泄露、篡改和未经授权的访问。本章节将介绍 Android 开…...

EDA实验设计-led灯管动态显示;VHDL;Quartus编程

EDA实验设计-led灯管动态显示;VHDL;Quartus编程 引脚配置实现代码RTL引脚展示现象记录效果展示 引脚配置 #------------------GLOBAL--------------------# set_global_assignment -name RESERVE_ALL_UNUSED_PINS "AS INPUT TRI-STATED" set_…...

Eclipse 查找功能深度解析

Eclipse 查找功能深度解析 Eclipse 是一款广受欢迎的集成开发环境(IDE),它为各种编程语言提供了强大的开发工具。在本文中,我们将深入探讨 Eclipse 的查找功能,这是开发者日常工作中不可或缺的一部分。无论是查找代码中的特定字符串,还是进行更复杂的搜索,如正则表达式…...

第三百二十九节 Java网络教程 - Java网络UDP套接字

Java网络教程 - Java网络UDP套接字 TCP套接字是面向连接的,基于流。基于UDP的套接字是无连接的,基于数据报。 使用UDP发送的数据块称为数据报或UDP数据包。每个UDP分组具有数据,目的地IP地址和目的地端口号。 无连接套接字在通信之前不建立…...

Leetcode215. 数组中的第K个最大元素(HOT100)

链接 第一次&#xff1a; class Solution { public:int findKthLargest(vector<int>& nums, int k) {sort(nums.begin(),nums.end());int n nums.size();return nums[n-k];} }; 这显然不能出现在面试中&#xff0c;因为面试官考察的不是这个。 正确的代码&#…...

QT与嵌入式——搭建串口

1、源码 由于我需要不止一个串口来进行数据交互&#xff0c;所以简单的封装了一下 void Usb_Init(QString portName, QSerialPort *Port) {Port->setPortName(portName);Port->setBaudRate(QSerialPort::Baud115200); // 设置波特率&#xff0c;根据你的开发板配置修改…...

Shell编程-6

声明&#xff1a;学习视频来自b站up主 泷羽sec&#xff0c;如涉及侵权马上删除文章 感谢泷羽sec 团队的教学 视频地址&#xff1a;shell(6)if条件判断与for循环结构_哔哩哔哩_bilibili 一、if条件判断 在Shell脚本中&#xff0c;if语句用于基于条件的评估来执行不同的代码块。…...

使用 Postman 设置 Bearer Token 进行身份验证

学习笔记 1. 打开 Postman 并创建新请求 打开 Postman。 在左上角点击 按钮&#xff0c;创建一个新的请求。 2. 选择 HTTP 方法 在请求类型&#xff08;默认为 GET&#xff09;旁边的下拉菜单中&#xff0c;选择你需要的 HTTP 方法&#xff0c;如 POST、GET、PUT 等。 3…...

现在转前端怎么样?

互联网技术日新月异&#xff0c;软件开发者追逐技术浪潮的脚步从未停歇。在这个快速发展的行业中&#xff0c;如何规划自己的职业道路&#xff0c;选择合适的技术方向&#xff0c;成为了许多开发者面临的重要抉择。本文将围绕技术选择这个话题&#xff0c;分享一些深入的思考和…...

【算法一周目】滑动窗口(1)

目录 长度最小的子数组 解题思路 代码实现 无重复字符的最大字串 解题思路 代码实现 最大连续1的个数l l l 解题思路 代码实现 将x减到0的最小操作数 解题思路 代码实现 长度最小的子数组 题目链接&#xff1a;209. 长度最小的子数组题目描述&#xff1a; 给定一个…...

React Native 基础

React 的核心概念 定义函数式组件 import组件 要定义一个Cat组件,第一步要使用 import 语句来引入React以及React Native的 Text 组件: import React from react; import { Text } from react-native; 定义函数作为组件 const CatApp = () => {}; 渲染Text组件...

【C++笔记】list使用详解及模拟实现

前言 各位读者朋友们大家好&#xff01;上期我们讲了vector的使用以及底层的模拟实现&#xff0c;这期我们来讲list。 目录 前言一. list的介绍及使用1.1 list的介绍1.2 list的使用1.2.1 list的构造1.2.2 list iterator的使用1.2.3 list capacity1.2.4 list element access1.…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”

2025年#高考 将在近日拉开帷幕&#xff0c;#AI 监考一度冲上热搜。当AI深度融入高考&#xff0c;#时间同步 不再是辅助功能&#xff0c;而是决定AI监考系统成败的“生命线”。 AI亮相2025高考&#xff0c;40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕&#xff0c;江西、…...

Web中间件--tomcat学习

Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机&#xff0c;它可以执行Java字节码。Java虚拟机是Java平台的一部分&#xff0c;Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...

从面试角度回答Android中ContentProvider启动原理

Android中ContentProvider原理的面试角度解析&#xff0c;分为​​已启动​​和​​未启动​​两种场景&#xff1a; 一、ContentProvider已启动的情况 1. ​​核心流程​​ ​​触发条件​​&#xff1a;当其他组件&#xff08;如Activity、Service&#xff09;通过ContentR…...

c# 局部函数 定义、功能与示例

C# 局部函数&#xff1a;定义、功能与示例 1. 定义与功能 局部函数&#xff08;Local Function&#xff09;是嵌套在另一个方法内部的私有方法&#xff0c;仅在包含它的方法内可见。 • 作用&#xff1a;封装仅用于当前方法的逻辑&#xff0c;避免污染类作用域&#xff0c;提升…...

VisualXML全新升级 | 新增数据库编辑功能

VisualXML是一个功能强大的网络总线设计工具&#xff0c;专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑&#xff08;如DBC、LDF、ARXML、HEX等&#xff09;&#xff0c;并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...