【Redis】-使用Lua脚本解决多线程下的超卖问题以及为什么?
一.多线程下引起的超卖问题呈现
1.1.我先初始化库存数量为1、订单数量为0

1.2.开启3个线程去执行业务
业务为:判断如果说库存数量大于0,则库存减1,订单数量加1
结果为:库存为-2,订单数量为3
原因:如下图所示,这是因为分别有6个指令(3个库存减1指令,3个订单数量加1指令)在redis服务端执行导致的。
namespace MengLin.Shopping.Redis.LuaScript
{
public class SecKillOriginal
{ static SecKillOriginal()
{
using (RedisClient client = new RedisClient("127.0.0.1", 6379))
{
//删除当前数据库中的所有Key, 默认删除的是db0
client.FlushDb();
//删除所有数据库中的key
client.FlushAll(); //初始化库存数量为1和订单数量为0
client.Set("inventoryNum", 1);
client.Set("orderNum", 0);
}
} public static void Show()
{
for (int i = 0; i < 3; i++)
{
Task.Run(() =>
{
using (RedisClient client = new RedisClient("127.0.0.1", 6379))
{
int inventoryNum = client.Get<int>("inventoryNum");
//如果库存数量大于0
if (inventoryNum > 0)
{
//给库存数量-1
var inventoryNum2 = client.Decr("inventoryNum");
Console.WriteLine($"给库存数量-1后的数量-inventoryNum: {inventoryNum2}");
//给订单数量+1
var orderNum = client.Incr("orderNum");
Console.WriteLine($"给订单数量+1后的数量-orderNum: {orderNum}");
}
else
{
Console.WriteLine($"抢购失败: 原因是因为没有库存");
}
}
});
}
}
}
}


二.使用Lua脚本解决多线程下超卖的问题以及为什么
2.1.修改后的代码如下
结果为:如下图所示,库存为0、订单数量为1,并没有出现超卖的问题且有2个线程抢不到。
namespace MengLin.Shopping.Redis.LuaScript
{
public class SecKillLua
{
/// <summary>
/// 使用Lua脚本解决多线程下变卖的问题
/// </summary>
static SecKillLua()
{
using (RedisClient client = new RedisClient("127.0.0.1", 6379))
{
//删除当前数据库中的所有Key, 默认删除的是db0
client.FlushDb();
//删除所有数据库中的key
client.FlushAll(); //初始化库存数量为1和订单数量为0
client.Set("inventoryNum", 1);
client.Set("orderNum", 0);
}
} public static void Show()
{
for (int i = 0; i < 3; i++)
{
Task.Run(() =>
{
using (RedisClient client = new RedisClient("127.0.0.1", 6379))
{
//如果库存数量大于0,则给库存数量-1,给订单数量+1
var lua = @"local count = redis.call('get',KEYS[1])
if(tonumber(count)>0)
then
--return count
redis.call('INCR',ARGV[1])
return redis.call('DECR',KEYS[1])
else
return -99
end";
Console.WriteLine(client.ExecLuaAsString(lua, keys: new[] { "inventoryNum" }, args: new[] { "orderNum" }));
}
});
}
}
}
}



三.为什么使用Lua脚本就能解决多线程下的超卖问题呢?
是因为Lua脚本把3个指令,分别是:判断库存数量是否大于0、库存减1、订单数量加1,这3个指令打包放在一起执行了且不能分割,相当于组装成了原子指令,所以避免了超卖问题。
在redis中我们尽量使用原子指令从而避免一些并发的问题。

【Redis】-使用Lua脚本解决多线程下的超卖问题以及为什么?的更多相关文章
- 使用Lua脚本通过原子减防止超卖
需求 双十二要搞一个一分钱门票抢购的活动. 分析 性能分析,抢购时会发生高并发,如果仅仅依靠Mysql数据库,有可能因为大量的请求频繁访问数据库造成服务器雪崩,所以考虑通过Redis减库存,最终的数据 ...
- 快速入门Redis调用Lua脚本及使用场景介绍
Redis 是一种非常流行的内存数据库,常用于数据缓存与高频数据存储.大多数开发人员可能听说过redis可以运行 Lua 脚本,但是可能不知道redis在什么情况下需要使用到Lua脚本. 一.阅读本文 ...
- Redis结合Lua脚本实现高并发原子性操作
从 2.6版本 起, Redis 开始支持 Lua 脚本 让开发者自己扩展 Redis … 案例-实现访问频率限制: 实现访问者 $ip 在一定的时间 $time 内只能访问 $limit 次. 非脚 ...
- 要想用活Redis,Lua脚本是绕不过去的坎
前言 Redis 当中提供了许多重要的高级特性,比如发布与订阅,Lua 脚本等.Redis 当中也提供了自增的原子命令,但是假如我们需要同时执行好几个命令的同时又想让这些命令保持原子性,该怎么办呢?这 ...
- redis中lua脚本的简单使用
一.背景 在使用redis的过程中,发现有些时候需要原子性去操作redis命令,而redis的lua脚本正好可以实现这一功能.比如: 扣减库存操作.限流操作等等. redis的pipelining虽然 ...
- 基于Lua脚本解决实时数据处理流程中的关键问题
摘要 在处理实时数据的过程中需要缓存的参与,由于在更新实时数据时并发处理的特点,因此在更新实时数据时经常产生新老数据相互覆盖的情况,针对这个情况调查了Redis事务和Lua脚本后,发现Redis事务并 ...
- 【spring boot】【redis】spring boot基于redis的LUA脚本 实现分布式锁
spring boot基于redis的LUA脚本 实现分布式锁[都是基于redis单点下] 一.spring boot 1.5.X 基于redis 的 lua脚本实现分布式锁 1.pom.xml &l ...
- .Net Core使用分布式缓存Redis:Lua脚本
一.前言 运行环境window,redis版本3.2.1.此处暂不对Lua进行详细讲解,只从Redis的方面讲解. 二.Redis的Lua脚本 在Redis的2.6版本推出了脚本功能,允许开发者使用L ...
- PHP中使用redis执行lua脚本示例
摸索了一下在PHP中如何使用redis执行lua脚本,写了一个脚本如下,供以后参考 <?php $redis = new Redis(); #实例化redis类 $redis->conne ...
- redis之lua脚本
背景介绍 redis数据库提供了一些管理功能比如 流水线:打包发送多条命令,并在一个回复里面接收所有被执行命令的结果.事务:一次执行多条命令,被执行的命令要么就全部都被执行,要么就一个也不执行.并且事 ...
随机推荐
- win10edge浏览器个人账户退出登录后再次登录自动登录问题
edge浏览器退出登录后,再次点击登录以同步数据会自动登录,可查看书签等个人数据 解决方法: 先在浏览器里面退出账户. 1.设置--电子邮件和账户--管理 2.登录后--安全--安全仪表板--高级安全 ...
- 使用scrollIntoView 使某元素滚动到指定位置
var el = document.getElementById('A'); el.scrollIntoView('true'); 知识: element.scrollIntoView(); // 使 ...
- Android Studio Dolphin 稳定版正式发布
作者 / Yuri Blaise, Product Manager, Android为了帮助开发者们更轻松地打造高质量应用,Android Studio 团队深入调研,为大家带来了最新稳定版 An ...
- 【MSSQL】数据类型的转换
类型转换 https://learn.microsoft.com/zh-cn/sql/t-sql/data-types/data-type-conversion-database-engine?vie ...
- StoneDB 子查询优化
StoneDB 子查询优化 摘要: 说明如何优化 exists 的 join 查询优化器的处理 核心函数: TwoDimensionalJoiner::ChooseJoinAlgorithm Join ...
- 韦东山005_ARM裸机1期加强版
005_ARM裸机1期加强版(又叫新1期,151节,23节免费,已完结)\新1期视频(151节,23节免费) 第006课开发板熟悉与体验(6节,免费) 第001节_开发板部件介绍与串口连接(免费) 如 ...
- 03-Spring使用注解方式注入
基于注解的DI注入 1.导包 环境搭建:导入aop包(spring-aop-4.1.6.RELEASE.jar) 2.创建类 3. 创建spring.xml配置文件(必须在src目录下) 该配置文件与 ...
- pom文件信息的解析
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://mave ...
- token解决cookie的弊端
token解决cookie的弊端 目录 token解决cookie的弊端 cookie的弊端 token解决弊端一 什么是token和JWT JWT的构成 token工作流程 token解决弊端二 C ...
- archlinux基本安装、以及图形化界面
磁盘刻录 在windows下载磁盘刻录工具 rufus,官网:https://rufus.ie/zh/ 中文界面,实在不是可以搜索一下磁盘刻录教程 在linux下使用balena-etcher,官网: ...