redis lua脚本相关知识点

redis的lua环境实现流程

  1. 服务器调用C的API创建一个Lua环境
  2. 将一些基础函数库导入到Lua环境中,并删除能载入外部文件的函数loadfile
  3. 创建redis函数的全局表格。函数包含了redis.call和redis.pcall、redis计算has值的函数,redis日志函数和返回错误的函数
  4. 使用redis自己的随机函数替代Lua原有随机函数,这是因为Lua原有随即函数有副作用,不符合redis对Lua函数的要求(无副作用,纯函数),redis自制随机函数,对于一样的seed,总生成相同的随机序列,如果不修改seed,则seed都是0
  5. 创建排序辅助函数:redis有一些“带有不确定性的命令”,相同的输入,返回的结果顺序可能不同,比如:SINTER、SUNION、SDIFF、SMEMBERS、HKEYS、HVALS、KEYS,它们不保证返回顺序每次一致,所以需要有辅助函数,在每次返回前对其排序
  6. 创建错误报告函数,提供出错更详细的信息
  7. 保护Lua的全局环境,确保不会滥用全局变量
  8. 将Lua环境保存到redisServer的lua属性中
  9. 创建lua环境协作组件:lua伪客户端和lua_script字典。其中伪客户端将执行脚本中所有redis命令并将结果再返回给脚本;而lua_script字典将记录所有被EVAL执行过和SCRIPT LOAD命令执行过的脚本,键为脚本SHA值,值为脚本内容

EVAL执行原理

  • 通过EVAL执行的脚本将保存到服务器lua_script字典中,并且创建一个”f_”开头,后接sha值的函数,脚本内容将会称为函数体,如果脚本通过redis.call或redis.pcall调用了redis命令,命令会发到lua伪客户端执行,然后将结果返回给脚本
  • 在脚本执行之前,服务器还需要设定一些钩子和传入参数等准备工作:将eval传入的建明和脚本参数保存到KEYS和ARGV数组中,传入lua环境、设置超时钩子

命令

  • EVAL "script_content":执行传入的脚本内容
  • EVALSHA <sha>:根据传入的sha值,查找是否有对应的函数,并执行函数,没有找到则返回错误
  • SCRIPT FLUSH:清空所有脚本,会清空并重建lua_script字典和lua环境
  • SCRIPT EXISTS <sha>:根据传入的sha值,判断对应的脚本是否存在在服务器中,通过检查lua_script字典
  • SCRIPT LOAD "script_content":将传入的脚本存入服务器,会在lua环境创建一个函数,并将脚本内容存入lua_script
  • SCRIPT KILLSHUTDOWN NOSAVE:脚本执行超过配置lua-time-limit的时长,如果没有写入操作,则传入SCRIPT KILL可以停止脚本执行,如果有写入操作,则需要命令SHATDOWN NOSAVE停止服务器以避免非法数据的写入

对于脚本的复制

  1. EVAL命令的复制:从服务器执行EVAL命令即可
  2. SCRIPT FLUSH:从服务器清空并重建lua环境和lua脚本字典
  3. SCRIPT LOAD:从服务器也执行相同的命令
  4. EVALSHA命令:因为主服务器和从服务器可能脚本环境有差别,通过sha查找函数并不一定能成功执行,所以,redisServer保存一个字典repl_scriptcache_dict,键是sha,值是null,当一个脚本被同步到了所有从服务器后,脚本的sha将会存入该字典。每当有新的从服务器连接,则该字典清空。
    当需要执行EVALSHA的复制的时候,如果脚本sha同时在lua_script和repl_scriptcache_dict两个字典中,则说明可以对从服务器使用相同命令复制,如果repl_scriptcache_dict字典没有对应sha,则EVALSHA命令将会转化成EVAL命令执行(通过lua_script字典拿到脚本内容)

猜你喜欢

转载自blog.csdn.net/lqadam/article/details/79429651