4月更文d22n22-java项目利用lua脚本实现redis操作原子性

159 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第22天,点击查看活动详情

java项目利用lua脚本实现redis操作原子性

前文

前文曾通过对于理论基础的叙述,对于redis操作原子性尤其在分布式高并发系统中的必要性进行过阐述。本文则主要结合一个实际需求,根据需求对于具体的操作进行实现。

实现方案

现在首先有这样的一个场景,我们在系统中预置了100个可处理单号,而此时有并发10000个客户端同时抢购。要求做到有且只有100人能够抢购到具体的单号。对于这个操作该怎么处理呢?这里便采用了lua脚本进行redis操作原子性束缚。通过lua脚本操作redis代替实际的redis。首先我们把需要操作的redis的键值,在java程序中传递给目标的lua脚本,以此在脚本中能够直接对于该键进行处理。每个请求到来后,在lua脚本中进行扣减1的操作,为了方便查看处理结果,我们同时将处理成功的数据存储到另一个redis键值之中。随后,为了模拟该并发请求,使用jmeter进行压测。在其中设置了10000个并发线程,每个线程同时对我们的测试接口进行访问。在执行结束后,到redis中查看实际剩余的数量以及成功操作的数量。

操作代码

--- 基础key值,用于标注剩余可获取数量
local key = KEYS[1]
--- 获取key2值,用于处理当前已操作的数量
local key2 = KEYS[2]
--- 获取一个参数 == 并不需要的参数
local val = ARGV[1]
--- 获取key值,如果找不到则
if redis.call("exists", key) == 1 then
    --- 如果插入成功,就去设置过期值
    if tonumber(redis.call("get", key)) > 0 then
        redis.call("set",key,tonumber(redis.call("get", key)) - 1)
        --- 处理当前操作的数目记录
        if redis.call("exists", key2) == 0 then
            redis.call("set",key2,1)
        else
            redis.call("set",key2,tonumber(redis.call("get", key2)) + 1)
        end
        return true
    else
        return false
    end
    return true
else
    return false
end

操作结果

经过上述方案的处理,可以看到最终的结果剩余订单数量为0,而记录的已操作数量为100,也就达到了目标的有且仅有100条订单信息可用。

image.png

image.png

后记

  • 千古兴亡多少事?悠悠。不尽长江滚滚流。