一:lua文件的作用

1、批量执行redis命令
2、保证redis命令能够原子执行

二:lua文件定义和使用

1、lua文件

--[[1、函数定义
]]--
--1、单品限流
local function seckillLimit()
local seckillLimitKey = ARGV[2];
-- 1、获取单品已经请求数量
local limitCount = tonumber(redis.call('get',seckillLimitKey) or "0");
local requestCountLimits = tonumber(ARGV[4]); --限制的请求数量
local seckillLimitKeyExpire = tonumber(ARGV[5]); --2秒过期
if limitCount + 1 > requestCountLimits then --超出限流大小
return 0,seckillLimitKeyExpire.."内只能请求"..requestCountLimits.."次";  --失败
else --请求数+1,并设置过期时间
redis.call('INCRBY',seckillLimitKey,"1")
redis.call('expire',seckillLimitKey,seckillLimitKeyExpire)
return 1; --成功
end
end--2、记录订单号:目的:创建订单方法幂等性,调用方网络超时可以重复调用,存在订单号直接返回抢购成功,不至于超卖
local function recordOrderSn()
local requestIdKey = ARGV[6]; -- 订单号key
local orderSn = ARGV[7]; -- 订单号
local hasOrderSn = tostring(redis.call('get',requestIdKey) or "");
if string.len(hasOrderSn) == 0 then
-- 存储订单号
redis.call('set',requestIdKey,orderSn);
return 1; -- 设置成功
else
return 0,"不能重复下单"; --失败
end
end--3、用户购买限制
local function userBuyLimit()
local userBuyLimitKey = ARGV[1]; -- 购买限制key
local productKey =KEYS[1]; --商品key
local productCount = tonumber(ARGV[3]);-- 商品数量
-- 1、用户已经购买数量
local userHasBuyCount = tonumber(redis.call('hget',userBuyLimitKey,"UserBuyLimit") or "0");
-- 2、获取限制的数量
local seckillLimit = tonumber(redis.call('hget',productKey,"SeckillLimit") or "0");
if userHasBuyCount + 1 > seckillLimit then --超出购买数量
return 0,"该商品只能购买"..seckillLimit.."件"; --失败
else --请求数+1,并设置过期时间
redis.call('HINCRBY',userBuyLimitKey,'UserBuyLimit',productCount)
return 1; --成功
end
end--4、扣减库存
local function subtractSeckillStock()
local productKey =KEYS[1]; --商品key
local productCount = tonumber(ARGV[3]);--商品数量
-- 1.1、扣减库存
local lastNum = redis.call('HINCRBY',productKey,"SeckillStock",-productCount);
-- 1.2、判断库存是否完成
if lastNum < 0 then
return 0,"秒杀已结束"; --失败
else
return 1; --成功
end
end--[[2、函数调用
]]--
--1、单品限流
local status,msg = seckillLimit();
if status == 0 then
return msg
end
--2、记录订单号;
local status,msg = recordOrderSn();
if status == 0 then
return msg
end--3、用户购买限制
status,msg = userBuyLimit();
if status == 0 then
return msg
end
--4、扣减秒杀库存
status,msg = subtractSeckillStock();
if status == 0 then
return msg
end
-- 返回成功标识
return 1;
--[[1、函数定义
]]--
--1、删除记录订单号:目的:创建订单方法幂等性,调用方网络超时可以重复调用,存在订单号直接返回抢购成功,不至于超卖
local function delRecordOrderSn()
local requestIdKey = ARGV[3]; -- 订单号key
local orderSn = ARGV[4]; -- 订单号
--删除订单号
redis.call('del',requestIdKey)
end--2、删除用户购买限制
local function delUserBuyLimit()
local userBuyLimitKey = ARGV[1]; -- 购买限制key
local productKey =KEYS[1]; --商品key
local productCount = tonumber(ARGV[2]);-- 商品数量
redis.call('HINCRBY',userBuyLimitKey,'UserBuyLimit',-productCount)
end--3、恢复库存
local function recoverSeckillStock()
local productKey =KEYS[1]; --商品key
local productCount = tonumber(ARGV[2]);--商品数量
-- 3.1、恢复库存
redis.call('HINCRBY',productKey,"SeckillStock",productCount);
end--[[2、函数调用
]]--
--1、删除记录订单号;
delRecordOrderSn();--2、撤销用户购买限制
delUserBuyLimit();--3、恢复秒杀库存
recoverSeckillStock();

2、IHostedService

/// <summary>
/// 服务启动加载秒杀Lua文件
/// </summary>
public class SeckillLuaHostedService : IHostedService
{private readonly IMemoryCache memoryCache;public SeckillLuaHostedService(IMemoryCache memoryCache){this.memoryCache = memoryCache;}/// <summary>/// 加载秒杀库存缓存/// </summary>/// <param name="cancellationToken"></param>/// <returns></returns>public Task StartAsync(CancellationToken cancellationToken){try{Console.WriteLine("加载执行lua文件到redis中");// 1、加载lua到redisFileStream fileStream = new FileStream(@"Luas/SeckillLua.lua", FileMode.Open);using (StreamReader reader = new StreamReader(fileStream)){string line = reader.ReadToEnd();string luaSha = RedisHelper.ScriptLoad(@line);// 2、保存luaSha到缓存中memoryCache.Set<string>("luaSha", luaSha);}Console.WriteLine("加载回滚lua文件到redis中");// 1、加载lua到redisFileStream fileStreamCallback = new FileStream(@"Luas/SeckillLuaCallback.lua", FileMode.Open);using (StreamReader reader = new StreamReader(fileStreamCallback)){string line = reader.ReadToEnd();string luaSha = RedisHelper.ScriptLoad(@line);// 2、保存luaShaCallback到缓存中memoryCache.Set<string>("luaShaCallback", luaSha);}}catch (Exception e){Console.WriteLine($"lua文件异常:{e.Message}");}return Task.CompletedTask;}public Task StopAsync(CancellationToken cancellationToken){return Task.CompletedTask;}
}

三:使用

// 9、加载seckillLua文件
services.AddHostedService<SeckillLuaHostedService>();
在这里插入代码片
/// <summary>
/// 4.3、创建订单(redis + 消息队列 + lua)
/// </summary>
/// <param name="orderDto"></param>
[HttpPost]
public PaymentDto CreateOrder(SysUser sysUser, [FromForm]OrderPo orderPo)
{*//* RedisHelper.Eval("SeckillLua.lua","222","3222","2222");RedisHelper.EvalSHA("dddddd"); key = "22222222222"; // 内存缓存MemroyCacheRedisHelper.ScriptLoad*//*// 1、redis秒杀开始string ProductKey = Convert.ToString(orderPo.ProductId);// 商品keystring SeckillLimitKey = "seckill_stock_:SeckillLimit" + orderPo.ProductCount; // 单品限流keystring UserBuyLimitKey = "seckill_stock_:UserId" + sysUser.UserId + "ProductId" + orderPo.ProductId;// 用户购买限制keyint productCount = orderPo.ProductCount; // 购买商品数量 2int requestCountLimits = 100; // 单品限流数量int seckillLimitKeyExpire = 1;// 单品限流时间var SeckillResult = RedisHelper.EvalSHA(memoryCache.Get<string>("luaSha"), ProductKey, UserBuyLimitKey, SeckillLimitKey, productCount, requestCountLimits, seckillLimitKeyExpire);if (!SeckillResult.ToString().Equals("1")){throw new BizException(SeckillResult.ToString());}// 1、创建订单号string orderSn = OrderUtil.GetOrderCode();// 2、扣减库存(redis缓存+redis扣减)seckillStockCache.SubtractSeckillStock(orderPo.ProductId, orderPo.ProductCount);// 3、发送订单消息到rabbitmqSendOrderCreateMessage(sysUser.UserId, orderSn, orderPo);// 6、创建支付信息PaymentDto paymentDto = new PaymentDto();paymentDto.OrderSn = orderSn;paymentDto.OrderTotalPrice = orderPo.OrderTotalPrice;paymentDto.UserId = sysUser.UserId;paymentDto.ProductId = orderPo.ProductId;paymentDto.ProductName = orderPo.ProductName;return paymentDto;
}

(更新时间)2021年6月4日 商城高并发秒杀系统(.NET Core版) 30-lua文件封装加载和执行相关推荐

  1. (更新时间)2021年5月28日 商城高并发秒杀系统(.NET Core版) 01-系统设计介绍

    秒杀项目 目标:从0到1构建一个高并发的秒杀系统 三个阶段 从0到1构建一个电商系统 从0到1构建秒杀系统 从0到1构建高并发秒杀系统 为了完成这个目标,我们需要知道几个前提 什么是电商 什么是秒杀 ...

  2. (更新时间)2021年6月2日 商城高并发秒杀系统(.NET Core版) 20-性能优化-系统配置

    性能测试的系统配置 操作系统参数 1.cpu 8核2.内存 16G3.硬盘 237G4.带宽 100M本机2088/ms 性能瓶颈原因 1.操作系统 ​ 如果是操作系统​ 没有任何软件,只有秒杀微服务 ...

  3. (更新时间)2021年6月3日 商城高并发秒杀系统(.NET Core版) 26-性能优化-nginx负载均衡优化

    一.关于Nginx的负载均衡 在服务器集群中,Nginx起到一个代理服务器的角色(即反向代理),为了避免单独一个服务器压力过大,将来自用户的请求转发给不同的服务器. 二.Nginx负载均衡策略 负载均 ...

  4. (更新时间)2021年6月5日 商城高并发秒杀系统(.NET Core版) 36-高并发秒杀项目k8s集群部署

    秒杀项目docker部署 前提准备 k8s集群网络 serviceSubnet: "10.96.0.0/16" podSubnet: "10.100.0.0/20&quo ...

  5. (更新时间)2021年5月11日 MongoDB数据库 MongoDB面试题

    MongoDB高频面试题 文章目录 MongoDB高频面试题 1.MongoDB是什么? 2.MongoDB有哪些特点? 3.MySQL与MongoDB之间最基本的差别是什么? 4.monogodb中 ...

  6. (更新时间)2021年5月12日 redis数据库 Redis面试题

    Redis高频面试题 文章目录 Redis高频面试题 1.什么是Redis?简述它的优缺点? 2.Redis相比memcached有哪些优势? 3.Redis支持哪几种数据类型? 4.Redis主要消 ...

  7. (更新时间)2021年5月15日 Nginx服务器 Nginx面试题

    Nginx面试题 1.什么是Nginx? Nginx是一个 轻量级/高性能的反向代理Web服务器,他实现非常高效的反向代理.负载平衡,他可以处理2-3万并发连接数,官方监测能支持5万并发,现在中国使用 ...

  8. (更新时间)2021年5月18日 C#.NET笔试题 高级篇

    C#.NET笔试题 高级进阶篇 文章目录 C#.NET笔试题 高级进阶篇 1.说说什么是架构模式. 2.架构的5大要素是哪5大要素? 3.说说什么事集群,什么是分布式. 4.说说对Redis的理解 5 ...

  9. (更新时间)2021年5月15日 SqlServer数据库 SqlServer面试题

    数据库SqlServer笔试题 文章目录 数据库SqlServer笔试题 一.数据库基础知识(通用)篇 1.说说主键.外键.超键.候选键 2.为什么用自增列作为主键? 3.触发器的作用是什么? 4.什 ...

最新文章

  1. windows查看端口占用 windows端口占用 查找端口占用程序 强制结束端口占用 查看某个端口被占用的解决方法 如何查看Windows下端口占用情况...
  2. okhttp 对应java版本_java – Android |在运行时获取OkHTTP库版本
  3. ffmpeg 从mp4上提取H264的nalu
  4. 蓝牙核心规范5.1:革新精确定位技术
  5. 如何解决Android SDK无法下载Package的问题(.net)
  6. java创建对象过七夕,想 new 个对象过七夕,她却抛了异常
  7. java哈夫曼_用 JAVA 实现哈夫曼树(Huffman Tree)
  8. 《Face alignment at 3000 FPS via Regressing Local Binary Features》阅读笔记
  9. spring boot2 整合(三)JOOQ工具
  10. 各大EMM厂商功能比较 第一部分 MDM比较
  11. h3c,nat网络地址转换
  12. QoS专题-第4期-QoS实现之限速
  13. 知识图谱实现公安情报分析(人工智能系列)
  14. Linux Shell基础教程
  15. linux/android中aplay/arecord用法以及命令
  16. 拉普拉斯变换和Z变换
  17. CSS单位px、em、rem、vh、vw、vmin、vmax
  18. 苹果市场金融类app上架ios1.2 ,5.2.1或3.21被拒原因解析
  19. 钓鱼邮件从入门到放弃
  20. 如何解决5万的并发量

热门文章

  1. 计算机专业哪些课程好难,计算机专业课程有哪些 学计算机难不难
  2. 互联网大厂打工人的 16 个心酸瞬间:生活很现实,都是为了挣钱!
  3. 击鼓传花击鼓次数相同c语言,击鼓传花
  4. 发布一个从迅雷下载字幕的小工具
  5. 火车头怎么采集图片-火车头采集图片并保存本地化
  6. 火车头如何html发布,火车头采集器教程:WEB在线发布模块的修改
  7. 终于搞懂了el-dialog属性modal-append-to-body,append-to-body的作用【图解】
  8. 微信实名认证是成年的,但游戏是未成年的,怎么改
  9. Python入门之类的继承
  10. 芯片验证需要围绕DUT做什么?