redis执行lua脚本

redis执行lua脚本

文档

  1. redis单机安装
  2. redis常用的五种数据类型
  3. springboot整合redis-RedisTemplate单机模式
  4. 布隆过滤器 -Bloom Filter

官方文档

  1. 官网操作命令指南页面:https://redis.io/docs/latest/commands/?name=get&group=string
  2. Redis cluster specification
  3. Distributed Locks with Redis

说明

  1. redis版本:7.0.0
  2. springboot版本:3.2.0

redis执行lua脚本

安装单机版redis
  1. 安装单机版redis参考文档:redis单机安装
编写lua脚本
  1. 在 Redis 中原子地尝试给 key 设值并设置过期时间,成功返回 1,失败(key 已存在)返回 0,用作分布式加锁。

  2. 编写一个lua脚本,为指定的 key 设置一个值并同时设置毫秒级过期时间,成功则返回 1,失败则返回 0。

  3. 脚本示例

    javascript 复制代码
    -- KEYS[1]  : 锁的 key
    -- ARGV[1]  : 锁的唯一标识
    -- ARGV[2]  : 过期时间(毫秒)
    -- 第一步:只有在 key 不存在时才设置值,相当于 SET key value NX
    
    if redis.call('SETNX', KEYS[1], ARGV[1]) == 1 then
      -- 第二步:设置过期时间,相当于 PX ttl
      redis.call('PEXPIRE', KEYS[1], ARGV[2])
      return 1       -- 加锁成功
    else
      return 0       -- 加锁失败(已有锁)
    end
  4. 简化成一行,保存为脚本文件tryLock.lua

    javascript 复制代码
    if redis.call('SETNX', KEYS[1], ARGV[1]) == 1 then redis.call('PEXPIRE', KEYS[1], ARGV[2]); return 1 else return 0 end
  5. 什么是KEYSARGV

    1. KEYS是一个数组,存放"所有 key 名"
    2. ARGV是一个数组,存放"所有非 key 的参数"
  6. 为什么区分KEYSARGV

    1. 技术上"都用 ARGV"在单机上多数能跑,但违反规范且在集群/路由/工具支持上会出问题
    2. Redis 之所以设计区分 KEYSARGV,就是为了让服务器明确知道哪些参数是 key,用于槽位路由、读写保护和各种内部/客户端工具对 key 的正确识别与处理。
lua脚本常见用法
  1. 常见用法是使用eval命令,传入lua脚本字符及参数,格式如下

    shell 复制代码
    EVAL script numkeys key [key ...] arg [arg ...]
    • script:Lua 脚本内容(字符串)
    • numkeys:后面有多少个 key
    • key key ...:传给脚本的 key 列表(用 KEYSi 访问)
    • arg arg ...:传给脚本的参数列表(用 ARGVi 访问)
  2. 示例,执行lua脚本

    shell 复制代码
    127.0.0.1:6379> EVAL "if redis.call('SETNX', KEYS[1], ARGV[1]) == 1 then redis.call('PEXPIRE', KEYS[1], ARGV[2]); return 1 else return 0 end" 1 myLockKey lockValue 30000
    (integer) 1
    • 1:有 1 个 key
    • myLockKeyKEYS[1]
    • lockValueARGV[1]
    • 30000ARGV[2](过期时间,毫秒)
加载lua脚本到内存
  1. 将lua脚本加载到内存中

    shell 复制代码
    127.0.0.1:6379> SCRIPT LOAD "if redis.call('SETNX', KEYS[1], ARGV[1]) == 1 then redis.call('PEXPIRE', KEYS[1], ARGV[2]); return 1 else return 0 end"
    "9aab773b2f1a82e88fcb760f3c42bbd9b9d3b1c3"
    • 返回值是一个 SHA1,使用EVALSHA 命令时会用到
    • 用同一段脚本内容再执行一次SCRIPT LOAD,会得到同一个 SHA
  2. 把 Lua 脚本加载到内存的作用

    核心作用:为了后面可以用 EVALSHA 复用脚本,减少网络传输和解析开销。

    • 性能更好:
      • 第一次用 SCRIPT LOAD 把脚本送到 Redis,服务器记住脚本内容和它的 SHA1。
      • 后面每次只发一个短短的 SHA1(EVALSHA ...),不用再把整段 Lua 文本发过去,也不用每次重新解析脚本。
    • 避免重复发送脚本:
      • 对于固定的业务脚本(比如分布式锁、库存扣减),脚本内容都是不变的,加载一次后就可以被很多次复用。
    • 方便客户端封装:
      • 客户端可以在启动时统一 SCRIPT LOAD 一批脚本,以 SHA1 为 ID 管理它们,调用时只用 EVALSHA 即可。
  3. 在shell中,可以通过读取lua脚本文件内容的方式将lua脚本加载到内存

    shell 复制代码
    cd /opt/module/redis/bin
    ./redis-cli -a 123456 SCRIPT LOAD "$(cat ../lua-data/tryLock.lua)"
    • 这种方式只能在 shell 中用 redis-cli 执行,不能在 redis-cli 里直接执行
检查lua脚本是否已加载
  1. 检查lua脚本是否已加载,实际上是检查lua脚本加载后返回的 SHA1是否存在

  2. 命令示例

    shell 复制代码
    127.0.0.1:6379> SCRIPT EXISTS 9aab773b2f1a82e88fcb760f3c42bbd9b9d3b1c3
    1) (integer) 1
    • 如果返回 1,表示已加载
    • 如果返回 0,表示这个 SHA 对应的脚本当前没在内存中
执行lua脚本
  1. 脚本先加载到内存:SCRIPT LOAD ,得到SHA值,用EVALSHA执行这个SHA值

    shell 复制代码
    127.0.0.1:6379> EVALSHA 9aab773b2f1a82e88fcb760f3c42bbd9b9d3b1c3 1 myLockKey lockValue 30000
    (integer) 1
  2. 直接执行脚本字符串:EVAL,这也是常见的用法

    shell 复制代码
    127.0.0.1:6379> EVAL "if redis.call('SETNX', KEYS[1], ARGV[1]) == 1 then redis.call('PEXPIRE', KEYS[1], ARGV[2]); return 1 else return 0 end" 1 myLockKey lockValue 30000
    (integer) 1
  3. 在shell中,通过脚本文件执行:redis-cli --eval tryLock.lua

    shell 复制代码
    ./redis-cli -a 123456 --eval ../lua-data/tryLock.lua myLockKey , lockValue 30000
    • 逗号前是 KEYS,逗号后是 ARGV

参考资料

  1. https://www.bilibili.com/video/BV13R4y1v7sP

注意事项

  1. 部分内容由AI生成
  2. 如有不对,欢迎指正!!!
相关推荐
武壮2 分钟前
Redis 跳表(Skip List)实现
redis·bootstrap·list
chushiyunen16 分钟前
金庸(庸老)小说之大模型
数据库·oracle
可乐ea19 分钟前
【知识获取与分享社区项目 | 项目日记第 23 天】项目梳理下篇:高并发与最终一致性复盘:Redis、Kafka、Outbox、ES 与 RAG 如何协同
java·redis·mysql·elasticsearch·缓存·ai·kafka
小此方29 分钟前
Re:Mysql数据库基础篇(二):MySQL 基础指南,架构分层、SQL 分类与引擎解析
数据库·mysql
一个儒雅随和的男子30 分钟前
深入剖析时序数据库 InfluxDB 核心原理
数据库·时序数据库
Nayxxu31 分钟前
GPT API 迁移教程:Chat Completions 到 Responses API 的最小改造路径
数据库·gpt
minji...36 分钟前
MySQL数据库 (三) 表的操作(增删查改),库和表的关系
数据库·mysql·数据表
西安邮电大学37 分钟前
分布式锁三种实现
java·redis·后端·其他·面试
xsc69967542 分钟前
Milvus实战:快速上手向量数据库
数据库·milvus
艾莉丝努力练剑42 分钟前
【Qt】事件
服务器·开发语言·网络·数据库·qt·tcp/ip·计算机网络