当前位置: 首页 > 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.…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)

引言 工欲善其事&#xff0c;必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后&#xff0c;我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集&#xff0c;就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...

java高级——高阶函数、如何定义一个函数式接口类似stream流的filter

java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用&#xff08;Math::max&#xff09; 2 函数接口…...

命令行关闭Windows防火墙

命令行关闭Windows防火墙 引言一、防火墙:被低估的"智能安检员"二、优先尝试!90%问题无需关闭防火墙方案1:程序白名单(解决软件误拦截)方案2:开放特定端口(解决网游/开发端口不通)三、命令行极速关闭方案方法一:PowerShell(推荐Win10/11)​方法二:CMD命令…...

[拓扑优化] 1.概述

常见的拓扑优化方法有&#xff1a;均匀化法、变密度法、渐进结构优化法、水平集法、移动可变形组件法等。 常见的数值计算方法有&#xff1a;有限元法、有限差分法、边界元法、离散元法、无网格法、扩展有限元法、等几何分析等。 将上述数值计算方法与拓扑优化方法结合&#…...

Redis——Cluster配置

目录 分片 一、分片的本质与核心价值 二、分片实现方案对比 三、分片算法详解 1. ‌范围分片&#xff08;顺序分片&#xff09;‌ 2. ‌哈希分片‌ 3. ‌虚拟槽分片&#xff08;Redis Cluster 方案&#xff09;‌ 四、Redis Cluster 分片实践要点 五、经典问题解析 C…...

【RabbitMQ】- Channel和Delivery Tag机制

在 RabbitMQ 的消费者代码中&#xff0c;Channel 和 tag 参数的存在是为了实现消息确认机制&#xff08;Acknowledgment&#xff09;和精细化的消息控制。 Channel 参数 作用 Channel 是 AMQP 协议的核心操作接口&#xff0c;通过它可以直接与 RabbitMQ 交互&#xff1a; 手…...

HTMLCSS 学习总结

目录 ​​​一、HTML核心概念​​ ​​三大前端技术作用​​ ​​HTML基础结构​​ 开发工具&#xff1a;VS Code 专业配置​​​​安装步骤​​&#xff1a; ​​二、HTML标签大全&#xff08;含表格&#xff09;​​ ​​三、CSS核心技术​​ 1. 三种引入方式对比 2.…...

Clickhouse统计指定表中各字段的空值、空字符串或零值比例

下面是一段Clickhouse SQL代码&#xff0c;用于统计指定数据库中多张表的字段空值情况。代码通过动态生成查询语句实现自动化统计&#xff0c;处理逻辑如下&#xff1a; 从系统表获取指定数据库&#xff08;替换your_database&#xff09;中所有表的字段元数据根据字段类型动态…...

fast-reid部署

配置设置&#xff1a; 官方库链接&#xff1a; https://github.com/JDAI-CV/fast-reid# git clone https://github.com/JDAI-CV/fast-reid.git 安装依赖&#xff1a; pip install -r docs/requirements.txt 编译&#xff1a;切换到fastreid/evaluation/rank_cylib目录下&a…...