第20章 Lua脚本

检查Lua环境初始化、伪客户端、EVAL/EVALSHA、脚本缓存、管理命令与复制传播 覆盖8个正式节点,并以Redis 3.0源码、故障和恢复对账验收。

学习目标

  • 能说明 Lua 脚本的原子执行特性
  • 能使用 EVALSHA 缓存调用脚本
  • 能分析脚本复制的按效果传播

为什么从“Lua脚本缓存与传播台”开始

第20章 Lua脚本的核心任务是检查Lua环境初始化、伪客户端、EVAL/EVALSHA、脚本缓存、管理命令与复制传播。命令返回值只暴露外层合同;实现解释还必须连接内存结构、写入与读取路径、事件顺序以及失败后的旧状态回收。Lua脚本缓存与传播台把这些关系放进同一条可复位轨迹。

先写预测:当调用方式由“EVALSHA命中”进入“EVALSHA未命中”时,哪个可观察状态最先变化?再规定什么结果会推翻当前解释。交互中的分数只表达透明因果方向,不冒充真实Redis测量。

来源、版次与独立重写边界

黄健宏作者读者服务页确认正式出版新版以Redis 3.0为源码基线,列出4部分、24章及完整小节,并链接Redis 3.0中文注释源码。本课程据此映射24个正式单元、145个目录节点,另设学习地图和总复习;未取得出版正文授权,目录只界定范围,不宣称复现原书正文。

本章字段与控制流由Redis官方3.0源码:scripting.c和作者注释源码交叉核对;Redis当前持久化文档只用于辨认版本差异。中文解释、图示、交互、实验与答案均为独立教学重写,不把目录页或代码仓库许可证误报为原书许可证。

本章术语与源码合同

第20章 Lua脚本必须守住“脚本在服务器中原子执行,Redis与Lua类型转换稳定,缓存摘要和复制传播对应同一脚本”。观察同时记录Lua脚本缓存与传播台一致率与脚本状态分叉风险;只有结构快照、函数入口、运行结果和故障反例互相一致,才接受实现结论。

⚡ 集群节点发现与握手
集群节点发现与握手(2 节点)N1:7000N2:7001gossip 协议:PING/PONG 携带随机节点信息,使拓扑收敛
操作日志
  1. 1.集群节点发现:通过 gossip 协议在节点间交换拓扑信息,新节点加入后逐步被全网感知。

作者目录逐项深读

创建并修改Lua环境

四级证据 1/8。 服务器创建单一Lua环境,载入Redis库、沙箱限制与辅助函数,并登记脚本缓存。本节点用“创建并修改Lua环境”作观察点,执行rg 'evalGenericCommand|scriptCommand|scriptingInit' src/scripting.c或等价源码探针,保存版本、输入、前后状态和能推翻解释的反例。

验证创建并修改Lua环境时,先预测调用方式从“EVALSHA命中”切到“EVALSHA未命中”会改变哪个字段、偏移、文件或消息;再固定脚本状态做一次对照。若故障注入没有破坏“脚本在服务器中原子执行,Redis与Lua类型转换稳定,缓存摘要和复制传播对应同一脚本”,就撤回当前解释而不是补写故事。

Lua环境协作组件

四级证据 2/8。 伪客户端把redis.call转为普通命令执行,超时钩子、排序辅助与类型转换共同约束脚本行为。本节点用“Lua环境协作组件”作观察点,执行rg 'evalGenericCommand|scriptCommand|scriptingInit' src/scripting.c或等价源码探针,保存版本、输入、前后状态和能推翻解释的反例。

验证Lua环境协作组件时,先预测调用方式从“EVALSHA命中”切到“EVALSHA未命中”会改变哪个字段、偏移、文件或消息;再固定脚本状态做一次对照。若故障注入没有破坏“脚本在服务器中原子执行,Redis与Lua类型转换稳定,缓存摘要和复制传播对应同一脚本”,就撤回当前解释而不是补写故事。

EVAL命令的实现

四级证据 3/8。 EVAL编译并执行脚本,KEYS与ARGV分离输入;脚本执行期间保持原子性但长运行会阻塞事件循环。本节点用“EVAL命令的实现”作观察点,执行rg 'evalGenericCommand|scriptCommand|scriptingInit' src/scripting.c或等价源码探针,保存版本、输入、前后状态和能推翻解释的反例。

验证EVAL命令的实现时,先预测调用方式从“EVALSHA命中”切到“EVALSHA未命中”会改变哪个字段、偏移、文件或消息;再固定脚本状态做一次对照。若故障注入没有破坏“脚本在服务器中原子执行,Redis与Lua类型转换稳定,缓存摘要和复制传播对应同一脚本”,就撤回当前解释而不是补写故事。

EVALSHA命令的实现

四级证据 4/8。 EVALSHA用脚本SHA1从缓存取已编译函数,未命中返回NOSCRIPT而不是自动获取正文。本节点用“EVALSHA命令的实现”作观察点,执行rg 'evalGenericCommand|scriptCommand|scriptingInit' src/scripting.c或等价源码探针,保存版本、输入、前后状态和能推翻解释的反例。

验证EVALSHA命令的实现时,先预测调用方式从“EVALSHA命中”切到“EVALSHA未命中”会改变哪个字段、偏移、文件或消息;再固定脚本状态做一次对照。若故障注入没有破坏“脚本在服务器中原子执行,Redis与Lua类型转换稳定,缓存摘要和复制传播对应同一脚本”,就撤回当前解释而不是补写故事。

脚本管理命令的实现

四级证据 5/8。 SCRIPT LOAD、EXISTS、FLUSH与KILL管理缓存和运行状态;KILL受脚本是否已写数据限制。本节点用“脚本管理命令的实现”作观察点,执行rg 'evalGenericCommand|scriptCommand|scriptingInit' src/scripting.c或等价源码探针,保存版本、输入、前后状态和能推翻解释的反例。

验证脚本管理命令的实现时,先预测调用方式从“EVALSHA命中”切到“EVALSHA未命中”会改变哪个字段、偏移、文件或消息;再固定脚本状态做一次对照。若故障注入没有破坏“脚本在服务器中原子执行,Redis与Lua类型转换稳定,缓存摘要和复制传播对应同一脚本”,就撤回当前解释而不是补写故事。

脚本复制

四级证据 6/8。 主节点必须让副本获得与实际执行等价的脚本或命令传播,摘要身份不能指向不同脚本文本。本节点用“脚本复制”作观察点,执行rg 'evalGenericCommand|scriptCommand|scriptingInit' src/scripting.c或等价源码探针,保存版本、输入、前后状态和能推翻解释的反例。

验证脚本复制时,先预测调用方式从“EVALSHA命中”切到“EVALSHA未命中”会改变哪个字段、偏移、文件或消息;再固定脚本状态做一次对照。若故障注入没有破坏“脚本在服务器中原子执行,Redis与Lua类型转换稳定,缓存摘要和复制传播对应同一脚本”,就撤回当前解释而不是补写故事。

重点回顾

四级证据 7/8。 第20章 Lua脚本的回顾要重新证明“脚本在服务器中原子执行,Redis与Lua类型转换稳定,缓存摘要和复制传播对应同一脚本”,并用同一输入比较结构前态、变更轨迹、故障首错与恢复后态

验证重点回顾时,先预测调用方式从“EVALSHA命中”切到“EVALSHA未命中”会改变哪个字段、偏移、文件或消息;再固定脚本状态做一次对照。若故障注入没有破坏“脚本在服务器中原子执行,Redis与Lua类型转换稳定,缓存摘要和复制传播对应同一脚本”,就撤回当前解释而不是补写故事。

参考资料

四级证据 8/8。 本章目录范围由作者页面确认,字段和控制流回到Redis 3.0的scripting.c与黄健宏注释源码核验;新版资料只承担差异说明

验证参考资料时,先预测调用方式从“EVALSHA命中”切到“EVALSHA未命中”会改变哪个字段、偏移、文件或消息;再固定脚本状态做一次对照。若故障注入没有破坏“脚本在服务器中原子执行,Redis与Lua类型转换稳定,缓存摘要和复制传播对应同一脚本”,就撤回当前解释而不是补写故事。

最小源码与运行切片

+git clone --branch 3.0 --depth 1 https://github.com/redis/redis.git redis-3.0
+cd redis-3.0
+rg 'evalGenericCommand|scriptCommand|scriptingInit' src/scripting.c

该切片固定Redis 3.0分支、编译器、配置、数据集和命令序列;先保存结构或函数位置,再运行隔离实例。任何持久化损坏、断线、故障转移、大键或高流量实验都必须使用临时数据并规定CPU、内存、磁盘、延迟和停止上限。

unit: rdi-20-lua
source_file: scripting.c
axis_a: "调用方式"
axis_b: "脚本状态"
fault: "让脚本执行阻塞事件循环却误判为并发,或缓存摘要与传播脚本不一致"
invariant: "脚本在服务器中原子执行,Redis与Lua类型转换稳定,缓存摘要和复制传播对应同一脚本"
replay: same_version_same_input

三个必须主动触发的误区

误区 1

现象 → 脚本里写死循环 原因 → 服务器被脚本锁死 修法 → 脚本保持短平快并设时限

误区 2

现象 → 频繁传全脚本 原因 → 带宽与解析浪费 修法 → SCRIPT LOAD + EVALSHA 缓存

误区 3

现象 → 脚本内做非确定操作 原因 → 复制回放结果分叉 修法 → 避免 RANDOMKEY/Time 等非确定命令

小结

  • Lua 脚本原子执行多步操作
  • EVAL 与 EVALSHA 两种调用
  • 脚本缓存减少传输与编译
  • 复制与 AOF 按效果传播
  • 脚本过长会阻塞服务器

练习、答案与节点验证

练习

问题 1: Lua 脚本的原子性边界在哪里?

问题 2: EVALSHA 相比 EVAL 的优势?

问题 3: 用 Lua 实现一个限流器:每秒最多 N 次请求。(独立实现)

术语复核与本章回顾

完成第20章 Lua脚本意味着能从scripting.c解释检查Lua环境初始化、伪客户端、EVAL/EVALSHA、脚本缓存、管理命令与复制传播,能运行章专属状态实验,能制造反例并在复位后证明旧状态没有残留。

资料与写作方式声明

本章以黄健宏《Redis设计与实现》(机械工业出版社)权威目录界定学习范围,并结合正文列出的技术资料独立重写;不宣称复现原书正文,也不沿用原作表述。

原作版权归作者与出版社所有;本站原创教学结构与表述仅供学习交流。

讨论

评论区加载中…