91免费视频Redis+Lua解决高并发场景在线秒杀问题

本文介绍了如何利用Redis的Lua脚本功能解决商品秒杀中的超卖问题。通过编写Lua脚本确保操作的原子性,减少数据库交互,提高性能。文章详细阐述了Lua脚本的编写、SHA秘钥的生成以及PHP代码的简化。同时,通过ab工具模拟并发测试,验证了方案的有效性,最终展示了只有10个用户在200并发情况下成功抢购,符合预期。
该文章已生成可运行项目,

为何要使用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脚本的+Lua解决高并发场景在线秒杀问题a秘钥,我们就可以在我们的代码中使用了。

$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来解决抢购秒杀类问题是当前比较流行的一种做法,希望对正在开发秒杀抢购功能的你能产生帮助。

本文章已经生成可运行项目
91手机助手是网龙公司推出的智能手机管理软件,下载吧提供最新苹果91手机助手下载,不但支持苹果iphone手机,还是一款全面支持Android、Symbian S60、iPhone、Wince、Windows Mobile五大智能手机系统的PC端管理软件。从此智能手机用户再也不用烦恼智能手机的繁复操作,只要有91手机助手,主题、壁纸、铃声、音乐、软件、电影、电子书的搜索、下载、安装都能轻松搞定!    可以通过91手机助手下载电子书并配合91熊猫看书软件进行移动阅读,通过RSS订阅新闻,极大节省了下载流量,连接91助手即可自动更新订阅RSS,为PC客户端与移动阅读搭建了无缝链接的桥梁。    目前已实现五大智能系统的跨平台资料互导,只需一键即可自动完成更换手机的资料转移,未来,将继续致力于为用户提供高效的智能手机应用管理解决方案,使用户可以十分便捷地对手机进行管理,只要拥有91手机助手,一切资料轻松匹配。 iphone苹果91手机助手功能介绍: 固件支持:iPhone 1.X | 2.X | 3.X | 4.X 固件 ; 支持 iTunes8.2 操作系统:支持32位和 64位的Windows XP / Vista / Windows 7 系统管理:系统信息查阅;进程管理;注册表管理等 阅读管理:几十万免费电子书在线/本地化管理;新闻RSS订阅等 资料管理:联系人管理、电脑收发管理短信、定制日程、管理任务 备份还原:备份还原短信、通话记录、主题铃声、联系人等十几种信息 媒体娱乐:轻松编辑设置手机铃声、手机主题、壁纸 软件管理:本地软件管理;海量手机软件免费安装 iphone苹果91手机助手软件特点: 完美个性体验-从界面到功能打造最安全最轻松的智能手机PC端管理工具 FREE/免费-都是免费的,91手机助手免费,软件游戏电子书也是免费的 海量资源尽情下载使用-真的是海量,几万手机软件,几十万电子书 轻松管理智能手机-还有什么比把智能机当傻瓜机玩更开心的呢? 91手机助手iPhone版V2.9.60.265修复日志: 1. 修复了iPod管理添加音乐部分用户无法在iPod列表中查看音乐的问题。 2. 修复对熊猫影音iPad版本已安装检查失败,造成一直提示安装的问题91手机助手相关软件下载: 下载吧提示您:91手机助手需要.NET Framework 2.0 运行环境,iPhone版 需要安装iTunes。 .NET Framework 2.0 下载:http://www.xiazaiba.com/html/517.html iPhone版必须控件iTunes 如果有最新的iTunes更新,请不要更新. iTunes for Windows下载地址:http://www.xiazaiba.com/html/438.html iTunes for Mac下载地址:http://www.xiazaiba.com/html/1484.html
高并发场景下选择 Redisson 还是 Redis + Lua 脚本,主要取决于性能需求、开发维护成本以及业务逻辑的复杂程度。 Redisson 提供了封装良好的分布式锁和原子操作功能,适用于需要快速实现分布式锁机制的场景。其优势在于简化了开发流程,开发者无需深入了解底层实现细节即可使用,适合业务逻辑相对简单、团队熟悉 Java 生态且不希望维护 Lua 脚本的情况[^1]。例如,使用 Redisson 实现一个简单的库存扣减操作可以通过以下代码完成: ```java RLock lock = redisson.getLock("inventoryLock"); lock.lock(); try { // 执行库存扣减逻辑 } finally { lock.unlock(); } ``` 然而,在高并发环境下,Redisson 的性能可能受到一定限制,因为其锁机制依赖于客户端竞争,可能导致额外的网络开销。 另一方面,Redis + Lua 脚本则适用于对性能有极致要求的场景,如秒杀或抢购活动。由于 Lua 脚本在 Redis 服务端执行,可以将多个操作合并为一个原子操作,从而确保数据一致性,并减少客户端与服务端之间的通信次数,提高响应速度。此外,当库存扣减逻辑较为复杂,比如涉及多商品联动或者库存预占时,Lua 脚本提供了更大的灵活性和控制力。例如,下面是一个用于库存扣减的 Lua 脚本示例: ```lua local key = KEYS[1] local decrease = tonumber(ARGV[1]) local current = redis.call('GET', key) if current and tonumber(current) >= decrease then return redis.call('DECRBY', key, decrease) else return -1 end ``` 此脚本保证了获取库存值和减少库存的操作是原子性的,避免了并发情况下超卖的问题。 对于功能扩展性和维护成本而言,Redisson 提供了标准化的客户端接口,降低了维护成本,但可能无法满足高度定制化的需求。而 Redis + Lua 脚本则需要团队具备一定的 Lua 编程能力,并且随着业务逻辑的增长,脚本的维护工作也会相应增加[^1]。 综上所述,在高并发场景下选择 Redisson 或 Redis + Lua 脚本时,应综合考虑项目的具体需求、团队的技术栈以及长期的维护策略。如果项目追求快速集成并且业务逻辑相对简单,那么 Redisson 是一个不错的选择;而对于那些对性能有极高要求以及需要处理复杂业务逻辑的应用,则更适合采用 Redis + Lua 脚本方案。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值