之前写了一篇PHP+Redis链表解决高并发下商品超卖问题,今天介绍一些如何使用PHP+Redis+Lua解决高并发下商品超卖问题。

为何要使用Lua脚本解决商品超卖的问题呢?

  • Redis在2.6版本后原生支持Lua脚本功能,允许开发者使用Lua语言编写脚本传到Redis中执行。
  • 将复杂的或者多步的redis操作,写为一个脚本,一次提交给redis执行,减少反复连接redis的次数,提升性能。
  • 原子操作。Redis会将整个脚本作为一个整体执行,中间不会被其他请求插入。因此在脚本运行过程中无需担心会出现竞态条件,无需使用事务。
  • 复用。客户端发送的脚本会永久存在redis中,这样其他客户端可以复用这一脚本,而不需要使用代码完成相同的逻辑。

首先,编写lua脚本,脚本名为secKill.lua:

-- 接收参数
local user_id = KEYS[1]
local goods_id = KEYS[2] -- 拼接字符串
local stock_key = "secKill:"..goods_id..":stock" -- 秒杀商品库存key
local users_key = "secKill:"..goods_id..":users" -- 成功秒杀商品的用户集合key -- 判断用户是否已经成功秒杀过该商品,如果已经存在在集合中,说明已经成功秒杀该商品,直接返回标志2,防止重复抢购
local user_exists = redis.call('sismember', users_key, user_id)
if tonumber(user_exists, 10) == 1 then
return 2
end -- 获取当前商品库存,如果库存小于等于0,表名商品已经被抢购完了,否则库存-1,并将抢购成功的用户放入集合中
local left_goods_count = redis.call('get', stock_key)
if tonumber(left_goods_count, 10) <= 0 then
return 0
else
redis.call('decr', stock_key)
redis.call('sadd', users_key, user_id)
end
return 1

上述代码中返回的数字0,1,2只是一种约定,自己可以根据自己的有业务约定不同状态返回的值。示例代码0:库存为0,1:秒杀成功,2:已秒杀成功的用户重复抢购。

lua脚本编写完成后,使用redis-cli命令生成该脚本的sha秘钥

redis-cli script load "$(cat /usr/local/redis/lua/secKill.lua)"
"63454a53284d9f6b30bdb6e5e12796a74f61f718"

最后,拿到lua脚本的sha秘钥,我们就可以在我们的代码中使用了。

$redis = new Redis();
$redis->connect("192.168.111.128", 6379);
$goodsId = 11211;
$userId = mt_rand(10000, 99999);
$res = $redis->evalSha('63454a53284d9f6b30bdb6e5e12796a74f61f718', [$userId, $goodsId], 2);

可以看到,我们将抢购逻辑写到lua脚本后,PHP代码就变得很少了,仅仅只有5行代码。

编写好代码,接着我们开始对上述代码进行测试。

首先,我们需要设置商品的库存量,正常逻辑是在后台商品管理页填写具体商品的库存量,此处假设我们的商品ID是11211(这个数字是不是很熟悉?是的,这是memcached的默认端口),商品数量为10个。

$redis-cli
> set secKill:11211:stock 10

我们使用ab压测工具模拟2000个用户并发量200来模拟抢购商品ID为11211的商品。

$ ab -n 2000 -c 200 http://www.master.com/index.php

如果没有ab工具需要使用 yum -y install httpd-tools安装

压测完成后,我们通过RedisDesktopManager(RDM)软件来查看抢购结果,可以看到即使是200的并发量,最终也只有10个用户抢购到商品,并且抢购成功的用户被写入到了secKill:11211:users的集合中,我们可以另外开一个守护进程专门用于从集合中获取用户ID处理后续事宜(将数据落盘写入数据库、给用户发短信等)

使用Redis+Lua来解决抢购秒杀类问题是当前比较流行的一种做法,希望对正在开发秒杀抢购功能的你能产生帮助。

Redis+Lua解决高并发场景抢购秒杀问题的更多相关文章

  1. 基于redis+lua实现高并发场景下的秒杀限流解决方案

    转自:https://blog.csdn.net/zzaric/article/details/80641786 应用场景如下: 公司内有多个业务系统,由于业务系统内有向用户发送消息的服务,所以通过统 ...

  2. 利用Redis锁解决高并发问题

    这里我们主要利用Redis的setnx的命令来处理高并发. setnx 有两个参数.第一个参数表示键.第二个参数表示值.如果当前键不存在,那么会插入当前键,将第二个参数做为值.返回 1.如果当前键存在 ...

  3. 利用 Redis 锁解决高并发问题

    这里我们主要利用 Redis 的 setnx 的命令来处理高并发. setnx 有两个参数.第一个参数表示键.第二个参数表示值.如果当前键不存在,那么会插入当前键,将第二个参数做为值.返回 1.如果当 ...

  4. Java电商项目,秒杀,抢购等高并发场景的具体场景和一些概念以及处理思路

    这里我借鉴了网上其他大佬的观点: 一:高并发带来的挑战 原因:秒杀抢购会经常会带来每秒几万的高并发场景,为了更快的返回结果给用户. 吞吐量指标QPS(每秒处理请求数),假设一个业务请求响应耗时为100 ...

  5. 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存

    原文:http://blog.csdn.net/heyewu4107/article/details/71009712 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存 问 ...

  6. 使用数据库乐观锁解决高并发秒杀问题,以及如何模拟高并发的场景,CyclicBarrier和CountDownLatch类的用法

    数据库:mysql 数据库的乐观锁:一般通过数据表加version来实现,相对于悲观锁的话,更能省数据库性能,废话不多说,直接看代码 第一步: 建立数据库表: CREATE TABLE `skill_ ...

  7. 【高并发】Redis如何助力高并发秒杀系统,看完这篇我彻底懂了!!

    写在前面 之前,我们在<[高并发]高并发秒杀系统架构解密,不是所有的秒杀都是秒杀!>一文中,详细讲解了高并发秒杀系统的架构设计,其中,我们介绍了可以使用Redis存储秒杀商品的库存数量.很 ...

  8. 利用redis实现分布式事务锁,解决高并发环境下库存扣减

    利用redis实现分布式事务锁,解决高并发环境下库存扣减   问题描述: 某电商平台,首发一款新品手机,每人限购2台,预计会有10W的并发,在该情况下,如果扣减库存,保证不会超卖 解决方案一 利用数据 ...

  9. php解决高并发问题

    我们通常衡量一个Web系统的吞吐率的指标是QPS(Query Per Second,每秒处理请求数),解决每秒数万次的高并发场景,这个指标非常关键.举个例子,我们假设处理一个业务请求平均响应时间为10 ...

随机推荐

  1. paramiko 详解

    Paramiko是用python语言写的一个模块,远程连接到Linux服务器,查看上面的日志状态,批量配置远程服务器,文件上传,文件下载等 初始化一些参数: host = "120.24.2 ...

  2. 书列荐书 |《刻意练习》安德斯&#183;艾利克森,罗伯特&#183;普尔著

    花了两天的时间,一气呵成的读完了这本书.凝练的精华就是:首先,世界上并没有真正的天才这一说.基因可能会起作用,但是经过后天大量的刻意练习,基因的这种作用会弱化.刻意练习需要专注.及时的反馈,并根据反馈 ...

  3. 安装Linux操作系统过程及出现的问题

    写在前面的话:由于是昨天装的,很多图片没来得及及时的保存,只好凭记忆回想,出现的问题只能回忆起大致的操作及应用软件. 另外,目前是小白一枚. 在安装时,我一开始想直接采用硬盘安装,参考帖子:http: ...

  4. AIoT开放平台及应用

    AIoT开放平台及应用 阿里AIoT开放平台,是阿里云IoT面向开发者的能力接入渠道,开发者可以在这里完成能力的申请.开通.部署.配置和集成开发等一些列工作.这些能力并不的独立交付,而是通过关联到行业 ...

  5. MindSpore后端运行类

    MindSpore后端运行类 Q:如何在训练过程中监控loss在最低的时候并保存训练参数? A:可以自定义一个Callback.参考ModelCheckpoint的写法,此外再增加判断loss的逻辑: ...

  6. FFmpeg扩展开发

    FFmpeg扩展开发 对FFmpeg RTMP/FLV部分做了扩展,用于支持H.265. 针对<video_file_format_spec_v10_1> VIDEODATA部分扩展如下: ...

  7. Java设计模式(4:里氏替换原则和合成复用原则详解

    一.里氏替换原则 如果说实现开闭原则的关键步骤就是抽象化,那么基类(父类)和子类的继承关系就是抽象化的具体实现,所以里氏替换原则就是对实现抽象化的具体步骤的规范.即:子类可以扩展基类(父类)的功能,但 ...

  8. springboot——简单通过Map将错误提示输出到页面显示

    主要思路:在controller层我们将错误信息put进map中,然后通过视图解析器跳转到目标页面,在目标页面中在通过指定标签内的th:text将错误消息取出. 例: 1.编写controller代码 ...

  9. 基于Docker安装常用软件

    基于Docker安装常用软件 本实验介绍如何基于Docker安装常用的软件,具体包括: Ubuntu Cetnos Nginx Node.js PHP MySQL Tomcat Redis Mongo ...

  10. PTA题目集7-9总结

    PTA题目集7-9总结 一.前言 题目集七:该题集为轮到图形卡片排序游戏题,主要考查的知识点有类的继承,ArrayList泛型的使用,Compabale接口的运用,多态的使用方法以及接口的应用,难度较 ...