Redis使用lua脚本实现库存扣减-今日快讯
Redis官方文档:https://redis.io/docs/manual/programmability/eval-intro/
Redis 保证脚本的原子执行。在执行脚本时,所有服务器活动在其整个运行期间都被阻止。这些语义意味着脚本的所有效果要么尚未发生,要么已经发生。
(资料图片)
脚本提供了几个在许多情况下都很有价值的属性。这些包括:
通过在数据所在的地方执行逻辑来提供局部性。数据局部性减少了整体延迟并节省了网络资源。确保脚本原子执行的阻塞语义。启用 Redis 中缺少的或过于小众的简单功能的组合。
Lua 允许您在 Redis 中运行部分应用程序逻辑。这样的脚本可以跨多个键执行条件更新,可能以原子方式组合几种不同的数据类型。
命令行应用LuaRedis Eval 命令使用 Lua 解释器执行脚本。
这里能帮我们实现 Redis 执行 Lua 脚本的命令有两个,一个是 EVAL,另一个是 EVALSHA。
redis Eval 命令基本语法如下:
EVAL script numkeys key [key ...] arg [arg ...]
其中 EVAL 是命令,script 是我们 Lua 脚本的字符串形式,numkeys 是我们要传入的参数数量,key 是我们的入参,可以传入多个,arg 是额外的入参。
以下尝试演示脚本KEYS和ARGV运行时全局变量之间输入参数的分布:
redis> EVAL "return { KEYS[1], KEYS[2], ARGV[1], ARGV[2], ARGV[3] }" 2 key1 key2 arg1 arg2 arg31) "key1"2) "key2"3) "arg1"4) "arg2"5) "arg3"
但这种方式需要每次都传入 Lua 脚本字符串,不仅浪费网络开销,同时 Redis 需要每次重新编译 Lua 脚本,对于我们追求性能极限的系统来说,不是很完美。所以这里就要说到另一个命令 EVALSHA 了,原生语法如下:
EVALSHA sha1 numkeys key [key ...] arg [arg ...]
不同的是这里传入的不是脚本字符串,而是一个加密串 sha1。这个 sha1 是从哪来的呢?它是通过另一个命令 SCRIPT LOAD 返回的,该命令是预加载脚本用的。
从脚本与 Redis 交互可以通过redis.call()或从 Lua 脚本调用 Redis 命令redis.pcall()。
两者几乎一模一样。两者都执行 Redis 命令及其提供的参数(如果这些参数表示格式正确的命令)。但是,这两个函数之间的区别在于处理运行时错误(例如语法错误)的方式。调用函数引发的错误redis.call()
直接返回给执行它的客户端。相反,调用redis.pcall()
函数时遇到的错误将返回到脚本的执行上下文,而不是进行可能的处理。
注意Lua 脚本并不会自动帮你完成回滚操作,如果你的脚本逻辑中包含两步写操作,需要自己去做回滚。好在我们库存扣减的逻辑针对 Redis 的命令就两种,一个读一个写,并且写命令在最后,这样就不存在需要回滚的问题了。
以库存扣减核心操作为例,完成核心 Lua 脚本的编写。其主要实现的功能就是查询库存并判断库存是否充足,如果充足,则做相应的扣减操作,脚本内容如下:
-- 调用Redis的get指令,查询活动库存,其中KEYS[1]为传入的参数1,即库存keylocal c_s = redis.call("get", KEYS[1])-- 判断活动库存是否充足,其中KEYS[2]为传入的参数2,即当前抢购数量if not c_s or tonumber(c_s) < tonumber(KEYS[2]) then return 0end-- 如果活动库存充足,则进行扣减操作。其中KEYS[2]为传入的参数2,即当前抢购数量redis.call("decrby",KEYS[1], KEYS[2])
然后我们将 Lua 脚本转成字符串,并添加脚本预加载机制。
预加载可以有多种实现方式,一个是外部预加载好,生成了 sha1 然后配置到配置中心,这样 Java 代码从配置中心拉取最新 sha1 即可。
另一种方式是在服务启动时,来完成脚本的预加载,并生成单机全局变量 sha1。我们这里先采取第二种方式,代码结构如下图所示:
以上是将 Lua 脚本转成字符串形式,并通过 @PostConstruct 完成脚本的预加载。然后新增 EVALSHA 方法,如下图所示:
方法入参为活动商品库存 key 以及单次抢购数量,并在内部调用 Lua 脚本执行库存扣减操作。看起来是不是很简单?在写完底层核心方法之后,我们只需要在下单之前,调用该方法即可,具体如下图所示:
脚本缓存到目前为止,我们已经使用EVAL命令来运行我们的脚本。
每当我们调用时EVAL,我们还会在请求中包含脚本的源代码。重复调用EVAL执行同一套参数化脚本,既浪费网络带宽,也对 Redis 有一定的开销。当然,节省网络和计算资源是关键,因此,Redis 为脚本提供了一种缓存机制。
您执行的每个脚本都EVAL存储在服务器保留的专用缓存中。缓存的内容由脚本的 SHA1 摘要总和组织,因此脚本的 SHA1 摘要总和在缓存中唯一标识它。您可以通过运行EVAL并随后调用来验证此行为INFO。
SCRIPT FLUSH | 从脚本缓存中移除所有脚本。 |
SCRIPT LOAD script | 将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本。 |
关键词:
下一篇:最后一页
- Redis使用lua脚本实现库存扣减-今日快讯
- CPO板块大幅走低,剑桥科技逼近跌停 世界观热点
- “一码贵州·产业应用聚合平台”第三期企业问诊活动暨小海星电子名片应用推介活动举行|今日讯
- “儿媳就是俺的亲闺女”
- 今年全球铂金供需缺口将创历史新高
- 心理学论文范文3000字 心理学论文范文|焦点快看
- 宜章县治超办:我为群众办实事,路政宣传送法入企业
- 大疆行业应用旗舰无人机官宣:5月18日发布_报道
-
晋阳高速牛王山隧道实现双洞贯通-天天新视野
晋阳高速牛王山隧道实现双洞贯通,主流媒体,山西门户。山西新闻网是经国务院新闻办审核批准,由山西日报报业
-
当前热门:5月15日基金净值:广发中证全指金融地产ETF最新净值0.9766,涨1.7%
该基金的基金经理为夏浩洋,夏浩洋于2021年5月20日起任职本基金基金经理,任职期间累计回报-13 06%。证券之
-
北京老旧小区改造居民需要出钱吗?
▶老旧小区改造居民需要出钱吗?答:部分内容需要出钱▶居民需要在哪些改造内容上出资?答:居民是老旧小区
-
【播资讯】消防安全漫画简笔画素材_消防安全漫画简笔画
纸、铅笔、彩笔准备纸、铅笔和彩笔先用铅笔在纸上画一个长方形,表示灭火器在灭火器上方画一个剪刀的形状,
X 关闭
X 关闭