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

Redis专题-秒杀

Redis专题-并发/秒杀

开局一张图,内容全靠“编”。

昨天晚上在群友里看到有人在讨论库存并发的问题,看到这里我就决定写一篇关于redis秒杀的文章。

imgimg

1、理论部分

我们看看一般我们库存是怎么出问题的

img

其实redis提供了两种解决方案:加锁和原子操作

1.1、加锁

加锁:其实非常常见,读取数据前,客户端先获取锁,再操作。
当客户端获得锁后,一直持有直到客户端完成操作,再释放。

怎么操作呢,客户端使用分布式锁来获取锁,(使用redis或者zookeeper来实现一个分布式锁)以商品的维度来加锁,在获取到锁的线程中,按顺序执行商品的库存查询和扣减,同时实现了顺序性和原子性。

img

但是,但是,有问题:
1、如果使用redis来实现分布式锁,那么锁的时效性是个问题。太短了,业务还没跑完锁就释放了。太长了,如果异常,其他业务就一直阻塞等着自动释放。

2、如果使用zookeeper,确实不用担心锁释放问题(临时节点),而且一致性好,但是性能不高。ZK中创建和删除节点只能通过Leader服务器来执行,然后Leader服务器还需要将数据同不到所有的Follower机器上,这样频繁的网络通信,性能的短板是非常突出的。(挖坑😂后续写一个redis和zookeeper实现分布式锁的文章)

所以。。继续往下看。。

1.2、原子操作

原子操作:执行过程中保持原子性操作,而原子性操作是不需要加锁的,也就是无锁操作。所以既保证了并发也不会减少系统并发性能。

redis的原子操作其实也有两种方式:
1、单命令操作:多个操作在redis中一个操作完成
2、lua:多个操作写成lua脚本,以原子性方式执行单个lua脚本

1.2.1、INCR/DECR

Redis 是使用单线程来串行处理客户端的请求操作命令的,所以,当 Redis 执行某个命令操作时,其他命令是无法执行的,这相当于命令操作是互斥执行的。

Redis 的单个命令操作可以原子性地执行,但是在实际应用中,数据修改时可能包含多个操作,至少包括读数据、数据增减、写回数据三个操作,这显然就不是单个命令操作了,那该怎么办呢?

Redis提供INCR/DECR,将读数据、数据增减、写回数据三个操作合并为了一个,可以对数据进行增值 / 减值操作,而且它们本身就是单个命令操作,所以本身具有互斥性。可以直接帮助我们进行并发控制。

// 将商量id的库存减1
DECR id

是的,就是这么简单就搞定了扣减库存。

1.2.2、Lua脚本

Redis 会把整个 Lua 脚本作为一个整体执行,在执行的过程中不会被其他命令打断,从而保证了 Lua 脚本中操作的原子性。

将要执行的操作编写到一个 Lua 脚本中,使用 Redis 的 EVAL 命令来执行脚本。

原生 EVAL 方法的使用语法如下:

EVAL script numkeys key [key ...] arg [arg ...]

script 是我们 Lua 脚本的字符串形式,numkeys 是我们要传入的参数数量,key 是我们的入参,可以传入多个,arg 是额外的入参。

但这种方式需要每次都传入 Lua 脚本字符串,不仅浪费网络开销,同时 Redis 需要每次重新编译 Lua 脚本,对于我们追求性能极限的系统来说,不是很完美。所以这里就要说到另一个命令 EVALSHA 了,原生语法如下:

EVALSHA sha1 numkeys key [key ...] arg [arg ...]

可以看到其语法与 EVAL 类似,不同的是这里传入的不是脚本字符串,而是一个加密串 sha1。这个 sha1 是从哪来的呢?它是通过另一个命令 SCRIPT LOAD 返回的,该命令是预加载脚本用的,语法为:

SCRIPT LOAD script

将 Lua 脚本先存储在 Redis 中,并返回一个 sha1,下次要执行对应脚本时,只需要传入 sha1 即可执行对应的脚本。这完美地解决了 EVAL 命令存在的弊端,所以我们这里也是基于 EVALSHA 方式来实现的。

-- 调用Redis的get指令,查询活动库存,其中KEYS[1]为传入的参数1,即库存key
local c_s = redis.call('get', KEYS[1])
-- 判断活动库存是否充足,其中KEYS[2]为传入的参数2,即当前抢购数量
if not c_s or tonumber(c_s) < tonumber(KEYS[2]) thenreturn 0
end
-- 如果活动库存充足,则进行扣减操作。其中KEYS[2]为传入的参数2,即当前抢购数量
redis.call('decrby',KEYS[1], KEYS[2])
return 1

我们可以将脚本先写在配置中心,代码执行的时候就去拉取最新的sha1。或者代码里面写死。

当然这个脚本也可以扩展,比如加上IP限制等等。但是太多操作放在Lua里也会降低redis的并发性能,所以非并发控制就不写到lua了。

理论看完了,实操一下吧

2、Talk is cheap. Show me the code

2.1、安装redis

跳过,不会安装的出门右拐。

我自己用podman。

podman run -p 6379:6379 --name my_redis --privileged=true -v D:\podman\redis\conf\redis.conf:/etc/redis/redis.conf  -v D:\podman\redis\data:/data -d docker.io/library/redis redis-server /etc/redis/redis.conf --appendonly yes

2.2、代码

在下.neter,就写C#代码了

[ApiController][Route("[controller]")]public class HomeController : ControllerBase{private static string _redisConnection = "localhost:6379";private static ConnectionMultiplexer _connMultiplexer;private string _redisScript = @"local c_s = redis.call('get', KEYS[1])if not c_s or tonumber(c_s) < tonumber(KEYS[2]) thenreturn 0endredis.call('decrby',KEYS[1], KEYS[2])return 1";private string _sha1 = string.Empty;/// <summary>/// 锁/// </summary>private static readonly object Locker = new object();private static int _count = 0;private static int _rushToPurchaseCount = 0;/// <summary>/// 获取 Redis 连接对象/// </summary>/// <returns></returns>private IConnectionMultiplexer GetConnectionRedisMultiplexer(){if ((_connMultiplexer == null) || !_connMultiplexer.IsConnected){lock (Locker){if ((_connMultiplexer == null) || !_connMultiplexer.IsConnected){_connMultiplexer = ConnectionMultiplexer.Connect(_redisConnection);} }}return _connMultiplexer;}[HttpPost("/Init")]public IActionResult Init(){GetConnectionRedisMultiplexer();return Ok();}[HttpPost]public async Task<IActionResult> Post(){System.Diagnostics.Stopwatch stopwatch = new Stopwatch();stopwatch.Start(); var db = _connMultiplexer.GetDatabase();var cache = db.ScriptEvaluateAsync(_redisScript,new RedisKey[] { "key999", "1" });var results = (string[]?)await cache;if (results[0] == "1"){Interlocked.Increment(ref _rushToPurchaseCount);Console.WriteLine($"恭喜您抢到了,{_rushToPurchaseCount}");}else{Console.WriteLine("很遗憾,您没有抢到");}return Ok();}}

我们在redis中新增5个库存

img

配置一下Jmeter,100个线程3秒内跑完

img

img

家人们!准备开枪!3!2!1!上链接!😆😆😆

img

让我们恭喜这5位大冤种😏

Jmeter聚合报告img

redis库存为0img

好了,到这里就先结束了。拜拜

github StackExchange手把手带你搭建秒杀系统-不差毫厘:秒杀的库存与限购Redis 核心技术与实战-无锁的原子操作:Redis如何应对并发访问?.Net Core使用分布式缓存Redis:Lua脚本

相关文章:

Redis专题-秒杀

Redis专题-并发/秒杀 开局一张图&#xff0c;内容全靠“编”。 昨天晚上在群友里看到有人在讨论库存并发的问题&#xff0c;看到这里我就决定写一篇关于redis秒杀的文章。 1、理论部分 我们看看一般我们库存是怎么出问题的 其实redis提供了两种解决方案&#xff1a;加锁和原子操…...

C++笔记之std::move和右值引用的关系、以及移动语义

C笔记之std::move和右值引用的关系、以及移动语义 code review! 文章目录 C笔记之std::move和右值引用的关系、以及移动语义1.一个使用std::move的最简单C例子2.std::move 和 T&& reference_name expression;对比3.右值引用和常规引用的经典对比——移动语义和拷贝语…...

ES6自用笔记

目录 原型链 引用类型&#xff1a;__proto__(隐式原型)属性&#xff0c;属性值是对象函数&#xff1a;prototype(原型)属性&#xff0c;属性值是对象 相关方法 person.prototype.isPrototypeOf(stu) Object.getPrototypeOf(Object)替换已不推荐的Object._ _ proto _ _ Ob…...

【BASH】回顾与知识点梳理(二十九)

【BASH】回顾与知识点梳理 二十九 二十九. 进程和工作管理29.1 什么是进程 (process)进程与程序 (process & program)子进程与父进程&#xff1a;fork and exec&#xff1a;进程呼叫的流程系统或网络服务&#xff1a;常驻在内存的进程 29.2 Linux 的多人多任务环境多人环境…...

Docker的Cgroup资源限制

Docker通过Cgroup来控制容器使用的资源配额&#xff0c;包括 CPU、内存、磁盘三大方面&#xff0c;基本覆盖了常见的资源配颡和使用量控制。 Cgoup 是CotrolGroups 的缩写&#xff0c;是Linux 内核提供的一种可以限制、记录、隔高进程组所使用的物理资源&#xff08;如CPU、内存…...

AI智能语音机器人的基本业务流程

先画个图&#xff0c;了解下AI语音机器人的基本业务流程。 上图是一个AI语音机器人的业务流程&#xff0c;简单来说就是首先要配置话术&#xff0c;就是告诉机器人在遇到问题该怎么回答&#xff0c;这个不同公司不同行业的差别比较大&#xff0c;所以一般每个客户都会配置其个性…...

uniapp 上传比较大的视频文件就超时

uni.uploadFile&#xff0c;上传超过10兆左右的文件就报错err&#xff1a;uploadFile:fail timeout&#xff0c;超时 解决&#xff1a; 在manifest.json文件中做超时配置 uni.uploadFile({url: this.action,method: "POST",header: {Authorization: uni.getStorage…...

CSS简介

目录 CSS CSS概念 核心概念 为什么需要CSS 语法 CSS的引入方式 内联样式&#xff08;行内样式&#xff09; 内部样式 外部样式&#xff08;推荐&#xff09; CSS CSS概念 CSS&#xff08;Cascading Style Sheets&#xff09;层叠样式表&#xff0c;又叫级联样式表&am…...

卡方分箱(chi-square)

统计学&#xff0c;风控建模经常遇到卡方分箱算法ChiMerge。卡方分箱在金融信贷风控领域是逻辑回归评分卡的核心&#xff0c;让分箱具有统计学意义&#xff08;单调性&#xff09;。卡方分箱在生物医药领域可以比较两种药物或两组病人是否具有显著区别。但很多建模人员搞不清楚…...

深入理解 Flutter 图片加载原理

作者&#xff1a;京东零售 徐宏伟 来源&#xff1a;京东云开发者社区 前言 随着Flutter稳定版本逐步迭代更新&#xff0c;京东APP内部的Flutter业务也日益增多&#xff0c;Flutter开发为我们提供了高效的开发环境、优秀的跨平台适配、丰富的功能组件及动画、接近原生的交互体验…...

【电子通识】什么是异常分析中的A-B-A方法

工作有了一定的经验之后&#xff0c;在做问题分析的时候&#xff0c;经常会听到别人说把这个部品&#xff08;芯片/模块&#xff09;拿去ABA一下&#xff0c;看看跟谁走。那么对于新人来说是否就会问一个问题&#xff1a;什么是ABA呢&#xff1f; A-B-A 交换是一种简单直接的交…...

[Linux] C获取键盘输入值

检测指令&#xff1a;cat /dev/input/event1 | hexdump 当键盘有输入时&#xff0c;会有对应的一堆16进制输出。它其实对应着input_event结构体【24字节】。 struct input_event ​​​​​​​{struct timeval time;__u16 type;__u16 code;__s32 value; }; #include <st…...

探索Python编程世界:开启你的代码之旅

亲爱的小伙伴们&#xff0c;大家好&#xff01;很高兴向大家推荐我的新专栏《Python编程指南&#xff1a;从入门到高级》。在这个专栏里&#xff0c;我将带领大家深入探索Python编程的奇妙世界&#xff0c;为您提供有趣、实用、易懂的内容&#xff0c;帮助您在编程的道路上越走…...

金融术语总结

洗钱 将犯罪或其他非法违法行为所获得的违法收入&#xff0c;通过各种手段掩饰、隐瞒、转化&#xff0c;使其在形式上合法化的行为。 存量客户 某个时间段里原先已有的客户,与新增客户相对应。 月活跃用户数量&#xff0c;MAU&#xff08;Monthly Active User&#xff0c;M…...

Linux驱动开发(Day5)

思维导图&#xff1a; 不同设备号文件绑定&#xff1a;...

[机器学习]特征工程:主成分分析

目录 主成分分析 1、简介 2、帮助理解 3、API调用 4、案例 本文介绍主成分分析的概述以及python如何实现算法&#xff0c;关于主成分分析算法数学原理讲解的文章&#xff0c;请看这一篇&#xff1a; 探究主成分分析方法数学原理_逐梦苍穹的博客-CSDN博客https://blog.csdn.…...

Python爬虫实战案例——第一例

X卢小说登录(包括验证码处理) 地址&#xff1a;aHR0cHM6Ly91LmZhbG9vLmNvbS9yZWdpc3QvbG9naW4uYXNweA 打开页面直接进行分析 任意输入用户名密码及验证码之后可以看到抓到的包中传输的数据明显需要的是txtPwd进行加密分析。按ctrlshiftf进行搜索。 定位来到源代码中断点进行调…...

一、openlayer开发介绍

首先需要引入openlayer api开发包。两种方式&#xff1a; 1、import方式&#xff0c;也就是npm安装&#xff0c;npm install ol 2、外部js引入。 下载地址&#xff1a;https://github.com/openlayers/openlayers 历史版本地址&#xff1a;Releases openlayers/openlayers …...

利用Jackson封装常用的JsonUtil工具类

在实际开发中&#xff0c;我们对于 JSON 数据的处理&#xff0c;通常有这么几个第三方工具包可以使用&#xff1a; gson&#xff1a;谷歌的fastjson&#xff1a;阿里巴巴的jackson&#xff1a;美国FasterXML公司的&#xff0c;Spring框架默认用的 由于以前一直用习惯了阿里的…...

阿里云2核4G服务器配置汇总表_轻量和ECS

阿里云2核4G服务器配置价格表&#xff0c;297元一年&#xff0c;配置为轻量应用服务器2核4G、4M带宽、60GB高效云盘&#xff0c;折合24元一个月。 目录 2核4G服务器轻量&#xff1a; 2核4G服务器ECS 关于轻量和ECS的区别&#xff1a; 2核4G服务器轻量&#xff1a; 云服务器…...

雪花算法替代MurmurHash后的提升(短链接项目中的唯一性设计)

短链接服务的核心功能&#xff0c;是将一个长网址&#xff08;比如几百个字符的 URL&#xff09;转换成一个短码&#xff0c;用户访问短码时&#xff0c;服务端会将其重定向回原始的长链接。 考虑到快速生成&#xff08;防止高并发下&#xff0c;性能变差&#xff09;和长变短的…...

智能电网RAG优化:闭环协同与精准检索

RAG论文原理解析、公式含义与错误点对点修正方案 一、论文核心原理详细解析(含场景举例) 本文针对通用RAG框架在术语密集、强监管垂直领域(智能电网)的三大原生适配瓶颈,提出了** RAG领域原生闭环协同RAG范式**,核心是将智能电网领域知识嵌入检索-生成-评估全生命周期,…...

门店做小程序失败的常见原因有哪些?

门店做小程序失败的常见原因有哪些&#xff1f;在实际经营中&#xff0c;越来越多门店开始尝试通过小程序实现线上转型&#xff0c;但上线后效果不佳甚至放弃运营的情况也较为常见。门店做小程序失败的常见原因&#xff0c;本质上并不在于工具本身&#xff0c;而在于经营逻辑、…...

HTML基础教程入门保姆级教学

什么是HTMLHTML全称Hyper Text Markup Language, 翻译成中文就是超文本标记语言&#xff0c;是一种最基础的网页开发语言, 需要注意的是HTML并不是编程语言 HTML 只有核心作用&#xff1a;搭建网页的结构和内容…...

7个关键步骤:用Meshroom实现高精度三维重建的完整指南

7个关键步骤&#xff1a;用Meshroom实现高精度三维重建的完整指南 【免费下载链接】Meshroom 3D Reconstruction Software 项目地址: https://gitcode.com/gh_mirrors/me/Meshroom 开源三维重建工具Meshroom凭借摄影测量实战技术&#xff0c;为用户提供了从二维图像到点…...

新手福音:在快马用ai生成你的第一个notepad编程入门项目

作为一个刚接触编程的新手&#xff0c;我完全理解那种面对空白编辑器时的迷茫感。还记得第一次想用Notepad写代码时&#xff0c;光是下载安装就折腾了半天。今天分享一个超实用的方法&#xff0c;用InsCode(快马)平台就能一键生成完整的入门指南&#xff0c;把下载、安装、写第…...

别再只用labelme了!用ENVI 5.3的ROI工具给遥感影像打标签,效率翻倍

遥感影像标注革命&#xff1a;ENVI 5.3 ROI工具如何让深度学习标签制作效率提升300% 当无人机航拍的高清影像铺满整个屏幕&#xff0c;标注员的手指在鼠标和键盘间机械重复着点击、拖拽、保存的动作——这是许多刚接触遥感影像深度学习的研究者再熟悉不过的场景。传统标注工具在…...

Scream:构建网络音频共享的虚拟声卡解决方案

Scream&#xff1a;构建网络音频共享的虚拟声卡解决方案 【免费下载链接】scream Virtual network sound card for Microsoft Windows 项目地址: https://gitcode.com/gh_mirrors/sc/scream 一、核心价值&#xff1a;突破物理限制的音频传输革命 在数字化办公与家庭娱乐…...

Windows右键菜单终极管理指南:用ContextMenuManager轻松掌控右键菜单

Windows右键菜单终极管理指南&#xff1a;用ContextMenuManager轻松掌控右键菜单 【免费下载链接】ContextMenuManager &#x1f5b1;️ 纯粹的Windows右键菜单管理程序 项目地址: https://gitcode.com/gh_mirrors/co/ContextMenuManager 还在为杂乱的Windows右键菜单烦…...

小红书内容采集效率革命:XHS-Downloader全方位解决方案

小红书内容采集效率革命&#xff1a;XHS-Downloader全方位解决方案 【免费下载链接】XHS-Downloader 小红书&#xff08;XiaoHongShu、RedNote&#xff09;链接提取/作品采集工具&#xff1a;提取账号发布、收藏、点赞、专辑作品链接&#xff1b;提取搜索结果作品、用户链接&am…...