NetCore/Net8下使用Redis的分布式锁实现秒杀功能
目的
本文主要是使用NetCore/Net8加上Redis来实现一个简单的秒杀功能,学习Redis的分布式锁功能。
准备工作
1.Visual Studio 2022开发工具
2.Redis集群(6个Redis实例,3主3从)或者单个Redis实例也可以。
实现思路
1.秒杀开始前,将商品的数量缓存到Redis中
2.使用Redis的分布式缓存锁,保证只有一个人能获取到锁,进而保证减库存的操作的原子性。
3.获取到Redis分布式锁后,开始后续的业务操作,减少库存。
实现代码
// See https://aka.ms/new-console-template for more information
using StackExchange.Redis;WriteLine("开始秒杀活动......");
WriteLine("请输入秒杀商品的ID,按回车键确认:", ConsoleColor.Blue);//ThreadPool.SetMinThreads(200, 200);var db = GetDataBase();string? productId = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(productId))
{int maxProductNumber = 100;//设置商品的最大库存数量await db.StringSetAsync($"ProductNumber:{productId}", maxProductNumber);//开始模拟购买List<Task> allTaskList = new List<Task>();for (int i = 0; i < 1000; i++){var task = BuyProduct(db, buyerId: i);allTaskList.Add(task);}await Task.WhenAll(allTaskList);int buySuccessNumber = Directory.GetFiles($"{AppContext.BaseDirectory}/buyer/").Length;WriteLine($"秒杀产品数量={maxProductNumber},购买成功用户数量={buySuccessNumber}", ConsoleColor.Green);Console.ReadLine();
}
else
{Console.WriteLine("输入商品ID为空,自动退出");
}IDatabase GetDataBase()
{ConnectionMultiplexer cm = ConnectionMultiplexer.Connect("127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381,127.0.0.1:6382,127.0.0.1:6383,127.0.0.1:6384");return cm.GetDatabase();
}async Task BuyProduct(IDatabase db, int buyerId)
{int threadId = Environment.CurrentManagedThreadId;try{//首先获取当前库存,判断是否还可以购买var leftProductNumber = await GetProductCurrentNumberAsync(db, productId);if (leftProductNumber < 1){WriteLine($"线程Id={threadId},购买失败,用户Id:{buyerId},库存不足1,当前库存:{leftProductNumber}", ConsoleColor.Red);return;}string key = $"ProductId:{productId}";string lockValue = Guid.NewGuid().ToString();//锁的过期时间一定要比成功获取锁后操作业务所需的时间长,//否则会导致业务还没有操作完成(减库存)锁就释放了,导致后面的用户获取到锁,最终导致超卖的情况bool lockSuccess = await GetLockAsync(db, key, lockValue, TimeSpan.FromSeconds(5));if (!lockSuccess){WriteLine($"线程Id={threadId},用户Id={buyerId},购买锁获取失败", ConsoleColor.Red);return;}try{//再次获取当前库存,判断是否还可以购买leftProductNumber = await GetProductCurrentNumberAsync(db, productId);if (leftProductNumber < 1){WriteLine($"线程Id={threadId},购买失败:{lockValue},用户Id:{buyerId},库存不足2,当前库存:{leftProductNumber}", ConsoleColor.Red);return;}//扣减库存await db.StringDecrementAsync($"ProductNumber:{productId}");WriteLine($"线程Id={threadId},购买成功:{lockValue},用户Id:{buyerId}", ConsoleColor.Green);var dirPath = $"{AppContext.BaseDirectory}/buyer";if (!Directory.Exists(dirPath)){Directory.CreateDirectory(dirPath);}await File.WriteAllTextAsync($"{dirPath}/buy-success-{buyerId}.txt", $"锁Id={lockValue},用户Id={buyerId},产品Id={productId},剩余产品数量={leftProductNumber}");}finally{bool lockReleased = await db.LockReleaseAsync(key, lockValue);if (!lockReleased){WriteLine($"线程Id={threadId},用户Id={buyerId},锁释放失败:{lockValue}", ConsoleColor.Yellow);}}}catch(Exception ex){WriteLine($"线程Id={threadId},用户Id={buyerId},购买失败:{ex}", ConsoleColor.Red);}
}async Task<bool> GetLockAsync(IDatabase db, string key, string lockValue, TimeSpan timeout)
{//每个用户有五次获取Redis分布式产品锁的机会,如果5次重试后,都没有获取到锁,则默认秒杀失败int i = 5;while (i > 0){bool lockSuccess = await db.LockTakeAsync(key, lockValue, timeout);if (lockSuccess){return true;}await Task.Delay(TimeSpan.FromMilliseconds(new Random(Guid.NewGuid().GetHashCode()).Next(100, 500)));i--;}return false;
}async Task<long> GetProductCurrentNumberAsync(IDatabase db, string productId)
{string? leftProductNumberString = await db.StringGetAsync($"ProductNumber:{productId}");_ = long.TryParse(leftProductNumberString, out long leftProductNumber);return leftProductNumber;
}static void WriteLine(string text, ConsoleColor colour = ConsoleColor.White)
{Console.ForegroundColor = colour;Console.WriteLine(text);
}
运行效果
相关文章:

NetCore/Net8下使用Redis的分布式锁实现秒杀功能
目的 本文主要是使用NetCore/Net8加上Redis来实现一个简单的秒杀功能,学习Redis的分布式锁功能。 准备工作 1.Visual Studio 2022开发工具 2.Redis集群(6个Redis实例,3主3从)或者单个Redis实例也可以。 实现思路 1.秒杀开始…...

openGauss学习笔记-102 openGauss 数据库管理-管理数据库安全-客户端接入之查看数据库连接数
文章目录 openGauss学习笔记-102 openGauss 数据库管理-管理数据库安全-客户端接入之查看数据库连接数102.1 背景信息102.2 操作步骤 openGauss学习笔记-102 openGauss 数据库管理-管理数据库安全-客户端接入之查看数据库连接数 102.1 背景信息 当用户连接数达到上限后&#…...
lspci源码
lspci 显示Linux系统的pci设备最简单的方法就是使用lspci命令,前提是要安装pciutils包(centos在最小化安装时不会自带该包,需要自己下载安装) pciutils包的源码github地址为: https://github.com/pciutils/pciutils …...
CMake教程-第 8 步:添加自定义命令和生成文件
CMake教程-第 8 步:添加自定义命令和生成文件 1 CMake教程介绍2 学习步骤Step 1: A Basic Starting PointStep 2: Adding a LibraryStep 3: Adding Usage Requirements for a LibraryStep 4: Adding Generator ExpressionsStep 5: Installing and TestingStep 6: Ad…...

快速入门:Spring Cache
目录 一:Spring Cache简介 二:Spring Cache常用注解 2.1:EnableCaching 2.2: Cacheable 2.3:CachePut 2.4:CacheEvict 三:Spring Cache案例 3.1:先在pom.xml中引入两个依赖 3.2:案例 3.2.1:构建数据库表 3.2.2:构建User类 3.2.3:构建Controller mapper层代码 3.…...

探索音频传输系统:数字声音的无限可能 | 百能云芯
音频传输系统是一项关键的技术,已经在数字时代的各个领域中广泛应用,从音乐流媒体到电话通信,再到多媒体制作。本文将深入探讨音频传输系统的定义、工作原理以及在现代生活中的各种应用,以帮助您更好地了解这一重要技术。 音频传输…...

【C++】-c++的类型转换
💖作者:小树苗渴望变成参天大树🎈 🎉作者宣言:认真写好每一篇博客💤 🎊作者gitee:gitee✨ 💞作者专栏:C语言,数据结构初阶,Linux,C 动态规划算法🎄 如 果 你 …...

《论文阅读28》OGMM
一、论文 研究领域: 点云配准 | 有监督 部分重叠论文:Overlap-guided Gaussian Mixture Models for Point Cloud Registration WACV 2023 二、概述 概率3D点云配准方法在克服噪声、异常值和密度变化方面表现出有竞争力的性能。本文将点云对的配准问题…...

忆联分布式数据库存储解决方案,助力MySQL实现高性能、低时延
据艾瑞咨询研究院《2022 年中国数据库研究报告》显示,截止2021年,中国分布式数据库占比达到 20%左右,主要以 MySQL 和 PostgreSQL 为代表的开源数据库为主。MySQL 作为备受欢迎的开源数据库,当前已广泛应用于互联网、金融、交通、…...

网络安全内网渗透之信息收集--systeminfo查看电脑有无加域
systeminfo输出的内容很多,包括主机名、OS名称、OS版本、域信息、打的补丁程序等。 其中,查看电脑有无加域可以快速搜索: systeminfo|findstr "域:" 输出结果为WORKGROUP,可见该机器没有加域: systeminfo…...

MySQL高可用架构学习
MHA(Master HA)是一款开源的由Perl语言开发的MySQL高可用架构方案。它为MySQL 主从复制架构提供了 automating master failover 功能。MHA在监控到 master 节点故障时,会提升其中拥有最新数据的 slave 节点成为新的 master 节点,在…...
seata的AT模式分析
(1)AT模式的核心组件: 事务协调器 TC 维护全局和分支事务的状态; 维护全局锁的状态; 接受TM的提交或者回滚命令,联系RM进行分支事务的提交或者回滚。 事务管理者 TM 开启全局事务,向TC申请…...

【算法练习Day22】 组合总和 III电话号码的字母组合
📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:练题 🎯长路漫漫浩浩,万事皆有期待 文章目录 组合总和 III剪枝 电话号码…...
react-------JS对象、数组方法实际应用集合
目录 1、向空对象里添加键值对 2、js在数组对象中添加和删除键值对(对象属性)的方法 2.1 添加 3、对已有的数据更换键值对的属性名 4、js字符串拼接、数组转字符串 5、从数组中提取元素 1、向空对象里添加键值对 对象的属性可以使用[ ] 或者 . 而…...
AWS SAP-C02教程6--安全
云的安全是一个重要的问题,很多企业不上云的原因就认为云不安全,特别是对安全性要求较高的企业,所以云安全是一个非常广泛且重要的话题,其实在之前章节中的组件都会或多或少讲述与其相关的安全问题,这里也会详细讲一下。本章主要通过讲述一些独立或与安全有关的组件以及网…...

Go学习第一章——开发环境安装以及快速入门(GoLand)
Go开发环境安装以及快速入门 一、环境配置1.1 go开发工具1.2 go sdk下载3.1 go相关命令行 二、快速入门2.1 创建项目2.2 创建.go程序文件2.3.配置 mod 的开启与关闭2.4 用 GoLand 写第一份代码2.5.代码静态检测(此部分非必要) 三、初步了解3.1 代码解释以…...
大数据学习(14)-Map Join和Common Join
&&大数据学习&& 🔥系列专栏: 👑哲学语录: 承认自己的无知,乃是开启智慧的大门 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言📝支持一下博>主哦&#x…...

Docker安装ES7.14和Kibana7.14(无账号密码)
一、Docker安装ES7.14.0 1、下载镜像 docker pull elasticsearch:7.14.0 2、docker安装7.14.0 mkdir -p /usr/local/elasticsearch/config mkdir -p /usr/local/elasticsearch/data chmod 777 -R /usr/local/elasticsearch/ echo "http.host: 0.0.0.0" >> /u…...

Zynq中断与AMP~双核串口环回之PS与PL通信
实现思路: 额外配置:通过PL配置计数器,向CPU0和CPU1发送硬中断。 1.串口中断CPU0,在中断中设置接收设置好字长的数据,如果这些数据的数值符合约定的命令,则关闭硬中断,并将这部分数据存入AxiLi…...

【一:实战开发testng的介绍】
目录 1、主要内容1.1、为啥要做接口测试1.2、接口自动化测试落地过程1.3、接口测试范围1.4、手工接口常用的工具1.5、自动化框架的设计 2、testng自动化测试框架基本测试1、基本注解2、忽略测试3、依赖测试4、超时测试5、异常测试6、通过xml文件参数测试7、通过data实现数据驱动…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...

【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...

android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

沙箱虚拟化技术虚拟机容器之间的关系详解
问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西,但是如果把三者放在一起,它们之间到底什么关系?又有什么联系呢?我不是很明白!!! 就比如说: 沙箱&#…...
Pydantic + Function Calling的结合
1、Pydantic Pydantic 是一个 Python 库,用于数据验证和设置管理,通过 Python 类型注解强制执行数据类型。它广泛用于 API 开发(如 FastAPI)、配置管理和数据解析,核心功能包括: 数据验证:通过…...