当前位置: 首页 > news >正文

Redis Lua 调试器(LDB)完全指南

1. 前言

Redis 3.2 起,官方为内嵌的 Lua 解释器配备了完整的远程调试器——LDB(Lua DeBugger)。
写复杂脚本时,你再也不必靠 redis.log() + 想象力“盲调”;LDB 提供 单步、断点、变量查看、命令跟踪 等桌面级 Debug 功能,而且在默认的 fork 模式下,不会破坏原有数据集,一次调完还能“重来一遍”。

2. LDB 总览

特性说明
客户端-服务器Redis 充当调试服务器;默认客户端是 redis-cli,也可按协议自写
Fork 会话新开子进程运行脚本,
主节点继续提供服务;会话结束即回滚数据
同步会话使用 --ldb-sync-mode 强制阻塞主库,
保留数据变更
断点支持行号断点、动态断点 (redis.breakpoint())
单步/继续step / next / continue
变量检查print 查看局部 / 全局 (KEYS, ARGV)
脚本日志redis.debug() 高亮打印
命令追踪单步模式下自动 Dump redis.call() 的命令与返回值

3. 调试会话模型

                +-------------------+
redis-cli (--ldb) <─RESP─► Redis Server|          ├─ main I/O|          └─ forked child (runs script with LDB)
  • Fork 模式(默认)

    1. Redis 主进程 fork() 创建子进程。
    2. 子进程加载脚本,进入调试;所有写操作仅影响子进程内存。
    3. 调试结束 → 子进程退出 → 一切回滚。
  • 同步模式 (--ldb-sync-mode)
    主进程直接调试脚本,调试期间 阻塞所有客户端,且数据修改会被保留。
    👉 仅在本地开发环境使用!

4. 快速上手

  1. 编写脚本 /tmp/script.lua

    local val = redis.call('INCR', KEYS[1])
    return val
    
  2. 启动调试

    redis-cli --ldb --eval /tmp/script.lua counter-key ,   # 逗号分隔 Keys 与 ARGV
    
  3. 第一行即断,输入 s (step) 执行当前行,或输入 c (continue) 跳到下一个断点。

5. 核心调试命令详解

缩写命令功能
s / nstep / next执行当前行,停在下一可执行行
ccontinue运行至下一个断点 / 脚本结束
llist [line] [ctx]查看源码。ll 0 查看当前位置;
l 1 1000000(或 whole) 打印全部
pprint [var]查看所有/指定局部变量;也支持 KEYS, ARGV
bbreakb 10 增加行 10 断点;b -10 删除;b 0 清全部
ttrace打印 Lua 调用栈
eeval <code>新帧执行 Lua 代码片段
rredis <cmd ...>手动发送 Redis 命令(调试态之上)
aabort同步模式下,保留 当前数据并终止脚本
maxlen [len]设置/查看打印裁剪长度;0 表示不限
restart重新加载脚本文件并重开会话
quit删除所有断点 → 继续执行 → 退出 redis-cli

6. 断点系统

6.1 静态断点

  • b 5 8 12:在第 5/8/12 行添加断点
  • 注意:只有被 Lua VM 真正执行的行 才能命中,如 local 声明或注释不会停。

6.2 动态断点 redis.breakpoint()

if tonumber(redis.call('GET', KEYS[1]) or 0) > 100 thenredis.breakpoint()   -- 命中后停在下一行
end

适合只在特定条件下停下来,省去反复手动 continue

7. 同步模式(非 Fork)

redis-cli --ldb-sync-mode --eval /tmp/script.lua
  • 调试期间 Redis 整体阻塞;脚本的写操作会真实落库。
  • 可随时用 abort 中断并保留已执行的部分。

8. 日志与状态检查

8.1 redis.debug()

redis.debug('keys=', KEYS, 'val=', redis.call('GET', KEYS[1]))
  • 仅在 LDB 会话中输出:

    <debug> line 3: "keys=", {"counter-key"}, "val=", "42"
    
  • 离开调试器后调用无任何副作用。

8.2 print / eval

  • print(无参)→ 打印当前帧所有局部
  • print foo → 深度查找上层帧的 foo
  • eval <lua> → 在独立帧执行 Lua(常用于快速测试函数)

9. 会话终止与重启

操作结果
脚本正常结束自动退出 LDB,redis-cli 恢复普通模式
Ctrl + C断开连接 → 会话终止(fork 会话数据回滚)
restart重新读取文件并开启新调试

10. 自定义调试客户端

LDB 使用标准 RESP 消息沟通,因此你可以在任何语言里:

  1. 打开 TCP 连接至 Redis;
  2. 发送 SCRIPT DEBUG YES
  3. 发送 EVAL <script> …;
  4. 按交互协议收发调试指令。

示例(Lua + redis-lua):

local redis = require 'redis'
redis.commands['ldbcontinue'] = redis.command('C')local script = [[local x, y = tonumber(ARGV[1]), tonumber(ARGV[2])local result = x * yreturn result
]]local cli = redis.connect('127.0.0.1', 6379)
cli:script('DEBUG', 'YES')
print(cli:eval(script, 0, 6, 9))   -- 断点停下
cli:ldbcontinue()                  -- 继续

11. 最佳实践与踩坑提示

  1. 永远在开发环境调试;生产库使用 fork 会话亦可能因子进程内存暴增而触发 OOM。
  2. 默认 fork 已回滚,若要保留变更慎用 --ldb-sync-mode
  3. 写复杂逻辑前先写单元测试;把 LDB 当“最后保险”。
  4. 长脚本宜拆功能函数,配合动态断点精确定位。
  5. 输出过大?用 maxlen 200 裁剪,或在脚本里自行 string.sub()
  6. 调试 RESP3 返回值时,可在脚本第一行 redis.setresp(3),便于打印 Map/Set。
http://www.dtcms.com/a/263517.html

相关文章:

  • 深度剖析 LNK 参数隐藏攻击 (ZDI-CAN-25373)
  • C++ Vector的使用(下)
  • 贪心算法在C++中的应用与实践
  • 基于动漫数据的可视化分析与推荐系统实现
  • Pyhton-EXCEL与Mysql数据对比
  • Monorepo+Pnpm+Turborepo
  • Vue Vue-route (1)
  • jvm的调优命令jstack打印堆栈信息阐述以及调优
  • Linux信号量
  • 基础算法合集-图论
  • 《AI的“三体进化”:数字基因与超人类思维的奇点降临》
  • Windows 11 24H2更新系统后WiFi不显示故障处理
  • AI编程实战:Cursor黑科技全解析
  • Python 数据分析与机器学习入门 (二):NumPy 核心教程,玩转多维数组
  • 【C语言】知识总结·内存函数
  • CSDN博客大搬家(本地下载markdown合适和图片本地化)
  • I/O I/O基本概念与基本I/O函数 6.30
  • Swift 实现二叉树垂直遍历:LeetCode 314 完整解析与实战示例
  • HTML之常用基础标签
  • Stable Diffusion 项目实战落地:从0到1 掌握ControlNet 第四篇 风格化字体大揭秘:从线稿到涂鸦,ControlNet让文字焕发新生
  • C#索引和范围:简化集合访问的现代特性详解
  • 湖北理元理律师事务所债务解法:从法律技术到生活重建
  • 使用nomachine远程连接ARM设备桌面
  • 【SpringAI】3.结构化输出,初级版
  • 大语言模型 API 进阶指南:DeepSeek 与 Qwen 的深度应用与封装实践
  • C# Winfrom教程(二)----label
  • Unity性能优化-渲染模块(1)-CPU侧(2)-DrawCall优化(2)GPUInstancing
  • StackGAN(堆叠生成对抗网络)
  • Qt Hello World 程序
  • js代码02