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

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式

今天是关于AI如何在教学中增强学生的学习体验&#xff0c;我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育&#xff0c;这并非炒作&#xff0c;而是已经发生的巨大变革。教育机构和教育者不能忽视它&#xff0c;试图简单地禁止学生使…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

wpf在image控件上快速显示内存图像

wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像&#xff08;比如分辨率3000*3000的图像&#xff09;的办法&#xff0c;尤其是想把内存中的裸数据&#xff08;只有图像的数据&#xff0c;不包…...

HTML前端开发:JavaScript 获取元素方法详解

作为前端开发者&#xff0c;高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法&#xff0c;分为两大系列&#xff1a; 一、getElementBy... 系列 传统方法&#xff0c;直接通过 DOM 接口访问&#xff0c;返回动态集合&#xff08;元素变化会实时更新&#xff09;。…...

Visual Studio Code 扩展

Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后&#xff0c;命令 changeCase.commands 可预览转换效果 EmmyLua…...

篇章二 论坛系统——系统设计

目录 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 1. 数据库设计 1.1 数据库名: forum db 1.2 表的设计 1.3 编写SQL 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 通过需求分析获得概念类并结合业务实现过程中的技术需要&#x…...