Lua 脚本功能是 Reids的一大亮点, 通过内嵌对 Lua 环境的支持,
Redis 解决了长久以来不能高效地处理 CAS (check-and-set) 命令的缺点。
并且可以通过组合使用多个命令, 轻松实现以前很难实现或者不能高效实现的模式。
该抢购方案基于Lua脚本,实际项目中可根据需要扩展命令。
伪代码
- 是否已抢购(是否达到抢购上限)
- 是否还有库存
- 如果未抢购、有库存则扣减,否则返回0
- 加入已抢购集合
- 加入购买处理队列
- 返回1
脚本
编写脚本
script.lua
1 | -- variable |
调试脚本
又是个坑:参数的分隔用逗号 ,
而且空格不能少
redis-cli --ldb --eval script.lua apple_stock apple_purchased_set apple_purchased_queue , 711
测试脚本
redis-cli
文本转换为命令:
1 | script load "-- variable\nlocal stockKey = KEYS[1]\nlocal purchasedKey = KEYS[2]\nlocal handlerKey = KEYS[3]\nlocal userId = ARGV[1]\n\n-- check purchased set\nif redis.call(\"SISMEMBER\", purchasedKey, userId) ~= 0 then return 0 end\n\n-- check stock\nlocal stock = redis.call(\"GET\", stockKey)\nif not stock or tonumber(stock) <= 0 then return 0 end\n\n-- stock decrease\nredis.call(\"DECR\", stockKey)\n-- add purchased set\nredis.call(\"SADD\", purchasedKey, userId)\n-- add purchased handler queue\nredis.call(\"LPUSH\", handlerKey, userId)\nreturn 1" |
得到sha1,执行命令:1
evalsha a80403df241c6d1823f5c820a4d2b6284995444e 3 apple_stock apple_purchased_set apple_purchased_queue 777
对比
lua
lua-cluster
watch
- lua 方案抢购先到先得,基本不会出现失败。
- lua 3个Master节点集群,性能对比单实例性能低。
- watch 方案里,会出现大概30%的抢购失败,且性能比lua方案低。
ps. 由于集群版的 Key 批量操作限制,mset、mget、eval,目前只支持具有 相同slot值的Key 执行批量操作。
所以在集群版的抢购方案中,传入的Key需要带上{}
把键值映射入相同的slot,让命令在一个节点执行。
例如:1
evalsha a80403df241c6d1823f5c820a4d2b6284995444e 3 apple_stock{apple} apple_purchased_set{apple} apple_purchased_queue{apple} 777
应用
- 可以把有原子性要求的操作放入脚本
- 监听
apple_purchased_queue
, 消费消息处理抢购。 - 如果架构里有MQ,可以去除脚本里的
LPUSH
。 - 消费者如果处理异常,可以使用延迟队列做”失败重试”、”失效检查”之类操作
队列&延迟队列:
https://www.cnblogs.com/shamo89/p/9873368.html
事务&lua&管道:
https://blog.csdn.net/u013870094/article/details/82461527
命令:
https://redis.io/commands#
https://redis.io/topics/ldb
https://redis.io/commands/script-load
https://redis.io/commands/evalsha
https://www.runoob.com/redis/redis-commands.html
LUA脚本:
https://yq.aliyun.com/articles/645851
https://blog.csdn.net/xixingzhe2/article/details/86167859
https://www.jianshu.com/p/366d1b4f0d13
https://www.jianshu.com/p/8028972cf735
https://www.runoob.com/lua/lua-miscellaneous-operator.html
异常:
Too many cluster redirections redis:
https://segmentfault.com/a/1190000016461888
https://blog.csdn.net/slg1988/article/details/93638501
https://blog.kelu.org/tech/2019/04/05/docker-compose-using-net-host.html
Connection reset:
https://www.cnblogs.com/liu-ke/p/7090698.html