【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实现锁的主从一致性。

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

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

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

相关文章

计算机网络socket编程(4)_TCP socket API 详解

个人主页:C忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C忠实粉丝 原创 计算机网络socket编程(4)_TCP socket API 详解 收录于专栏【计算机网络】 本专栏旨在分享学习计算机网络的一点学习笔记,欢迎大家在评论区交流讨论&…

Jmeter数据库压测之达梦数据库的配置方法

目录 1、概述 2、测试环境 3、数据库压测配置 3.1 安装jmeter 3.2 选择语言 3.3 新建测试计划 3.4 配置JDBC连接池 3.5 配置线程组 3.6 配置测试报告 3.7 执行测试 1、概述 Jmeter是Apache组织开发的基于Java的压力测试工具,用于对软件做压力测试。 它最…

RAG与微调:大模型落地的最佳路径选择(文末赠书)

一、大模型技术发展现状 自2022年底ChatGPT掀起AI革命以来,大语言模型(LLM)技术快速迭代发展,从GPT-4到Claude 2,从文心一言到通义千问,大模型技术以惊人的速度发展。然而,在企业实际应用场景中…

Web 入门

HTTP 一、概念 Hyper Text Transfer Protocol,超文本传输协议,规定了浏览器和服务器之间数据传输的规则。 二、特点 基于TCP协议:面向连接,安全。基于请求-响应模型的:一次请求对应一次响应。HTTP协议是无状态的协…

pinia是什么?pinia简介快速入门,创建pinia到vue3项目中

一,pinia就是Vuex,的替代工具,Vuex plus 如何将pinia引入到vue3项目中? 1.首先新建一个vue3项目 全填yes npm init vuelatest 2.安装好之后查阅官方文档 pinia使用文档 3.从而得知在项目中有俩种方式安装pinia 我的本地只有nod…

Java 基于SpringBoot+vue框架的老年医疗保健网站

大家好,我是Java徐师兄,今天为大家带来的是Java Java 基于SpringBootvue框架的老年医疗保健网站。该系统采用 Java 语言开发,SpringBoot 框架,MySql 作为数据库,系统功能完善 ,实用性强 ,可供大…

FPGA实现串口升级及MultiBoot(九)BPI FLASH相关实例演示

本文目录索引 区别一:启动流程的区别区别二:高位地址处理区别三:地址映射例程说明总结例程地址之前一直都是以SPI FLASH为例进行相关知识讲解,今天我们介绍另一款常用的配置FLASH-BPI FLASH。 今天的讲解以简洁为主,主打个能用一句话不说两句话。以和SPI区别为主,实例演…

VisionPro 机器视觉案例 之 彩色保险丝个数统计

第十四篇 机器视觉案例 之 彩色保险丝颜色识别个数统计 文章目录 第十四篇 机器视觉案例 之 彩色保险丝颜色识别个数统计1.案例要求2.实现思路2.1 方法一 颜色分离工具CogColorSegmenterTool将每一种颜色分离出来,得到对应的单独图像,使用斑点工具CogBlo…

实时数据研发 | Flink技术栈

下周要开始接触一些实时的内容了,想来是很幸运的,这是我在新人培训上提问过技术前辈的问题:“想学习实时相关技术,但是部门没有类似的需求,应该如何提升?”当时师姐说先用心去学,然后向主管证明…

Spring cloud 一.Consul服务注册与发现(4)

1.动态刷新案例步骤 1.问题 接着上一步,我们在consul的dev配置分支修改了内容马上访问,结果无效 会发现还是原来的内容,/(ㄒoㄒ)/~~ ,没有做到及时响应和动态刷新 2.步骤 RefreshScope主启动类添加 package com.atguigu.cloud;import org.springfram…

石油化工调度台的外观如何设计更有科技感

在石油化工行业中,调度台作为生产运营的核心指挥中枢,其设计不仅关乎操作效率,更是企业形象和技术实力的体现。那么,到底如何在调度台的外观设计中融入科技感,以提升工作效率并彰显企业前沿形象,成为了一个…

【机器学习】——朴素贝叶斯模型

💻博主现有专栏: C51单片机(STC89C516),c语言,c,离散数学,算法设计与分析,数据结构,Python,Java基础,MySQL,linux&#xf…

如何使用Jest测试你的React组件

在本文中,我们将了解如何使用Jest(Facebook 维护的一个测试框架)来测试我们的React组件。我们将首先了解如何在纯 JavaScript 函数上使用 Jest,然后再了解它提供的一些开箱即用的功能,这些功能专门用于使测试 React 应…

Stm32f103X HAL库 串口DMA空闲中断学习 踩坑记

捡 了一个Stm32f103X的工控板, 开发工具是 STM32cubeide ,复制了之前闲的时候建的一个485通讯的空工程,只配置了圈中的引脚,用的是usart3 ,增加了需要用的io,编程器是网上几块钱买的jlink-ob,带模拟串口的. 在学习串口通信的过程中总感觉不太顺利 ,刚开始用串口中断…

云服务器部署WebSocket项目

WebSocket是一种在单个TCP连接上进行全双工通信的协议,其设计的目的是在Web浏览器和Web服务器之间进行实时通信(实时Web) WebSocket协议的优点包括: 1. 更高效的网络利用率:与HTTP相比,WebSocket的握手只…

PDF内容提取,MinerU使用

准备环境 # python 3.10 python3 -m pip install huggingface_hub python3 -m pip install modelscope python3 -m pip install -U magic-pdf[full] --extra-index-url https://wheels.myhloli.com下载需要的模型 import json import osimport requests from huggingface_hub…

掌握 Spring 事务管理:深入理解 @Transactional 注解

在业务方法上使用Transactional开启声明式事务时,很有可能由于使用方式有误,导致事务没有生效。 环境准备 表结构 CREATE TABLE admin (id bigint(20) unsigned NOT NULL AUTO_INCREMENT,username varchar(255) DEFAULT NULL,password varchar(255) …

设计模式之 观察者模式

观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听一个主题对象(Subject)。当主题对象的状态发生变化时,所有依赖于它的观察者都会得到…

【python】将word文档内容转换为excel表格

在日常工作中,我们经常需要将Word文档中的内容提取并转换为Excel表格,以便进行数据分析和处理。本文将介绍如何使用Python编写一个简单的程序,将Word文档中的内容转换为Excel表格。 一.实例 使用以下word文档作为例子: 工具界面如…

Linux|进程程序替换

目录 什么是进程替换 替换原理 exec函数 exec* 函数的共性 什么是进程替换 进程程序替换是指将一个进程中正在运行的程序替换为另一个全新的程序的过程,但替换不是创建新进程,只是将对应程序的代码和数据进行替换。具体来说,这个替换过程涉…