Lua 脚本

Lua 是一种轻量级脚本语言 Redis 在内部嵌入了 Lua 解释器(用 C 实现)

👉 也就是说:

复制代码
Redis(C写) + Lua解释器(C写) → 支持执行Lua脚本

为了讲清楚 Lua 脚本,小编帮你把 Lua 在 Redis 里的作用讲清楚,从"为什么存在 → 解决什么问题 → 怎么用"这条路线开始。

🧠 一、先纠正一个关键理解

由于 Redis 是 C 语言编写的,那 Lua 也是 语言封装了一层的工具吗?

部分对,但不完整

✅ 更准确的说法是:

Lua 是一种轻量级脚本语言

Redis 在内部嵌入了 Lua 解释器(用 C 实现)

【真实情况】Redis(C写) + Lua解释器(C写) → 支持执行Lua脚本

🚀 二、Redis 为什么要支持 Lua?

👉 核心一句话:

复制代码
让多个命令"原子执行 + 一次完成"

❌ 没有 Lua 的问题

比如你做一个业务:

复制代码
库存判断 + 扣库存

普通写法:

复制代码
if (GET stock > 0) {
    DECR stock
}

🚨 问题来了(并发下):

复制代码
线程A: GET → 1
线程B: GET → 1
线程A: DECR → 0
线程B: DECR → -1 ❌

👉 超卖问题


🔥 三、Lua 的核心价值


✅ 1️⃣ 原子性(最重要🔥)

复制代码
Lua 脚本在 Redis 中执行 = 单线程 + 原子执行

👉 等价于:

复制代码
整个脚本 = 一个命令

✅ 2️⃣ 减少网络往返(性能)

复制代码
多次 Redis 请求 → 变成一次 EVAL

✅ 3️⃣ 业务逻辑下沉到 Redis

复制代码
逻辑在 Redis 内执行,而不是客户端拼

🧩 四、Redis Lua 是怎么工作的?


👉 执行方式

复制代码
EVAL "lua脚本" key数量 key1 key2 ... arg1 arg2 ...

📌 示例(库存扣减)

复制代码
local stock = tonumber(redis.call('GET', KEYS[1]))

if stock > 0 then
    return redis.call('DECR', KEYS[1])
else
    return -1
end

👉Lua 执行

复制代码
EVAL "
local stock = tonumber(redis.call('GET', KEYS[1]))
if stock > 0 then
    return redis.call('DECR', KEYS[1])
else
    return -1
end
" 1 stock

🔥 五、Lua vs 事务(MULTI/EXEC)


👉 很多人误区:Lua = 事务?

❌ 不一样


对比一下:

|------|----------|--------------|
| 特性 | Lua | Redis事务 |
| 原子性 | ✅ 强原子 | ⚠️ 弱(中间可能失败) |
| 支持逻辑 | ✅ if/for | ❌ 不支持 |
| 回滚 | ❌ 不支持 | ❌ 也不支持 |
| 并发安全 | ✅ | ⚠️ 依赖WATCH |


🧠 本质区别

复制代码
Lua = "可编程原子操作"
事务 = "命令打包执行"

🧪 六、再给你一个真实业务例子(限流)


👉 需求:

复制代码
1秒最多访问5次

Lua 实现:

复制代码
local count = redis.call('INCR', KEYS[1])

if count == 1 then
    redis.call('EXPIRE', KEYS[1], 1)
end

if count > 5 then
    return 0
else
    return 1
end

👉 调用:

复制代码
EVAL "脚本" 1 user:limit

🧠 这段做了什么?

复制代码
INCR + EXPIRE + 判断 → 原子执行

🧨 七、Lua 在 Redis 中的本质定位


👉 一句话总结

复制代码
Lua = Redis 内部的"小型业务执行引擎"

👉 再换一种更工程化说法

复制代码
它让 Redis 从:
👉 KV存储

变成:

👉 支持业务逻辑执行的"内存计算节点"

🚀 八、Lua 语法

学 Redis Lua,不是为了学 Lua 本身,而是:

复制代码
👉 用 Lua 在 Redis 里写"原子业务逻辑"

所以学习重点是:

复制代码
Redis思维 > Lua语法

Java 调 Redis:
    多次网络请求 + 客户端控制逻辑

Lua in Redis:
    一次请求 + Redis内部执行逻辑 + 原子保证

🥇 第一阶段:Lua 最小语法(够用就行)

👉 目标:能看懂 & 写简单脚本

  • Lua 基础语法(变量、if、for)
  • redis.call
  • KEYS / ARGV

1️⃣ 变量

复制代码
local a = 10
local b = "hello"

2️⃣ if 判断

复制代码
local x = 5

if x > 3 then
    return 1
else
    return 0
end

3️⃣ 基本类型

复制代码
number(数字)
string(字符串)
boolean(布尔)
nil(空)

4️⃣ 函数(了解即可)

复制代码
local function add(a, b)
    return a + b
end

👉 在 Redis Lua 中很少写复杂函数


🥈 第二阶段:Redis Lua 核心(重点🔥)

👉 这一阶段才是真正关键

  • 原子操作设计(库存 / 限流 / 幂等)
  • 脚本复用(EVALSHA)

1️⃣ redis.call(最重要)

复制代码
redis.call("GET", "key")
redis.call("SET", "key", "value")

📌 示例

复制代码
local value = redis.call("GET", "name")
return value

2️⃣ KEYS 和 ARGV(必须掌握)


👉 KEYS(Redis key)
复制代码
KEYS[1]
KEYS[2]

👉 ARGV(参数)
复制代码
ARGV[1]
ARGV[2]

📌 示例

复制代码
local key = KEYS[1]
local value = ARGV[1]

redis.call("SET", key, value)
return "OK"

👉 调用方式

复制代码
EVAL "脚本" 1 mykey myvalue

解释:

复制代码
1 = key数量
mykey → KEYS[1]
myvalue → ARGV[1]

🥉 第三阶段:核心能力(真正有价值🔥)


1️⃣ 原子操作(核心)

👉 Redis Lua 最大价值:

复制代码
多个操作 → 一次执行(原子)

📌 示例:安全扣库存

复制代码
local stock = tonumber(redis.call("GET", KEYS[1]))

if stock <= 0 then
    return -1
end

redis.call("DECR", KEYS[1])
return 1

🚨 重点

复制代码
整个脚本 = 原子操作(不会被打断)

2️⃣ 限流(经典面试题🔥)

复制代码
local count = redis.call("INCR", KEYS[1])

if count == 1 then
    redis.call("EXPIRE", KEYS[1], 1)
end

if count > 5 then
    return 0
else
    return 1
end

3️⃣ 幂等控制(防重复)

复制代码
if redis.call("EXISTS", KEYS[1]) == 1 then
    return 0
else
    redis.call("SET", KEYS[1], 1)
    return 1
end

🏅 第四阶段:进阶(拉开差距🔥)


1️⃣ EVALSHA(脚本缓存)

复制代码
第一次 → EVAL
之后 → EVALSHA(更快)

2️⃣ 性能 & 风险(很重要⚠️)


❗ Redis Lua 是单线程执行

复制代码
脚本执行期间 → Redis 被阻塞

🚨 禁忌

复制代码
❌ 死循环
❌ 大量计算
❌ 长时间运行

3️⃣ 设计原则

复制代码
✔ 脚本要短
✔ 逻辑要简单
✔ 只做必要操作

🧪 第五阶段:从 0 到 1 的练习(强烈建议你做)

我给你一个入门练习顺序👇


🥇 练习 1:读写

复制代码
SET + GET

🥈 练习 2:计数器

复制代码
INCR + 返回结果

🥉 练习 3:库存扣减

复制代码
GET + 判断 + DECR

🏅 练习 4:限流(重点)

复制代码
INCR + EXPIRE + 判断

🔥 最后一句话总结

复制代码
Lua = 让 Redis 具备"执行业务逻辑能力"的武器
相关推荐
Yeauty3 小时前
渲染成图再 CLI 拼接,还是进程内直推?Rust 帧到视频的两条路
开发语言·rust·音视频
geovindu3 小时前
CSharp: Breadth First Search Algorithm and Depth First Search Algorithm
开发语言·后端·算法·c#·.net·搜索算法
库克克4 小时前
【C++】set 与multiset
开发语言·c++
Wang's Blog4 小时前
Go-Zero项目开发34: 微服务超时控制与重试机制实践
开发语言·微服务·golang·go-zero
2zcode5 小时前
项目文档:基于MATLAB神经网络的心力衰竭预测与临床辅助决策系统研究
开发语言·神经网络·matlab·心力衰竭预测\
减瓦5 小时前
深入 Quarkus:云原生时代 Java 的重生之路
java·开发语言·云原生
杨运交5 小时前
[053][核心模块]Java枚举缓存与ORM集成实践
java·开发语言·缓存
2401_894915536 小时前
Geo优化系统源码部署搭建技术——PHP程序开发部署指南
开发语言·php
wuyk5556 小时前
67.嵌入式C语言进阶:结构体指针实战指南——STM32外设、传感器数据访问的高效技巧
c语言·开发语言·stm32·单片机
找磁材6 小时前
空心杯电机与永磁体
开发语言·磁性材料·钕铁硼·磁钢