zoukankan      html  css  js  c++  java
  • Redis之eval+lua实现初步

    目录

    目录 1

    1. 前言 1

    2. 执行方式 1

    3. 执行过程 3

    4. 使用原则 3

    1. 前言

    Redis的实现保证eval的执行是原子的,即使eval执行的lua超时,Redis也不会自动终止执行。

    官方说明如下:

    When a script reaches the timeout it is not automatically terminated by Redis since this violates the contract Redis has with the scripting engine to ensure that scripts are atomic.

    2. 执行方式

    截止到5.0.5版本,Redis都是将lua解释为一MULTI+EXEC方式执行。当执行以下Redis语句时:

    eval "redis.call('set',KEYS[1],ARGV[1]);redis.call('set',KEYS[2],ARGV[2])" 2 k1 k2 12 ab

    观察它的AOF文件,可以发现内幕:

    *1 // 1表示参数个数,包括命令令本身,也就是说命令不带参数

    $5 // 第一个参数的字节数,MULTI命令为五个字节

    MULTI // Redis命令字

    *3 // 表示共三个参数,包括命令字本身

    $3

    set // Redis命令字

    $2 // 为“k1”的字节数

    k1 // Redis Key

    $2 // 为“12”的字节数

    12 // Redis Value

    *3

    $3

    set // Redis命令字

    $2

    k2

    $2

    ab

    *1

    $4

    EXEC

    如果lua脚本有语法错误,可能导致部分执行,如执行下述脚本:

    eval "redis.call('set',KEYS[1],ARGV[1]);redis.call('incrby',KEYS[2],ARGV[2])" 2 k1 k2 ab 12

    将得到错误:

    ERR Error running script (call to f_de45a142dc8b96e1634403ac2a3f4ccfef4d9dc9): @user_script:1: ERR value is not an integer or out of range

    原因是前一段脚本已将k2的值设置为ab,因此为非整数值,不能对该Keyincrby操作。这个时候AOF将只记录已成功执行部分:

    *1

    $5

    MULTI

    *3

    $3

    set

    $2

    k1

    $2

    ab

    *1

    $4

    EXEC

    所以在使用lua之前,一定要先测试好,排除掉语法错误。不然因Redis不支持回滚,会出现中间状态。如果确实需要回滚,也应当在同一段lua中完成提交或回滚。

    Redis缓存每一段执行的lua脚本,并且不会主动释放,除非外部调用Redis命令“SCRIPT FLUSH”。Redis对执行的lua脚本做SHA,并用SHA值唯一标识该段lua脚本,后续可直接调用evalsha来执行该脚本,从而避免每次调用传入大段lua脚本。

    另外,也可以执行Redis命令“SCRIPT KILL”来主动终止正在执行的lua脚本。但能终止的lua脚本仅限还未执行过写(write)操作,如果被KILLlua脚本已执行了任意写操作,则“SCRIPT KILL”不能终止它的执行,这样约束的原因是为保证eval命令的原子性,不出现中间结果。

    如果仍然要终止已执行写操作的lua脚本,只能通过执行“SHUTDOWN NOSAVE”方式,以阻止中间结果(half-written)的存在。

    对于复杂的lua脚本 ,可执行redis-cli并指定参数“--ldb”,即可简单快捷的调试lua脚本。

    3. 执行过程

    Lua的执行过程如下:

    -> 调用lua脚本解释器执行lua脚本

    -> lua脚本解释器将lua脚本翻译成redis命令

    -> redis状态机中应用lua脚本所执行到的redis命令

    -> redis以MULTI+EXEC方式将所执行的redis命令写入到AOF文件

    -> 响应客户端执行结果

    4. 使用原则

    使用eval+lua最好遵守以下原则:

    1) 执行时间尽可能短,一定要小于连接的超时时长,可使用命令slowlog get”观察实际情况;

    2) 在应用到生产环境之前,测试保证没有语法错误;

    3) 不要硬编码KeyValue到脚本中,不然缓存lua脚本的内存越积越多。

  • 相关阅读:
    如何在文本编辑器中实现搜索功能? 字符串比较算法 BF算法 RK算法
    怎么读源码 读源码的一些技巧
    系统性学习
    堆 二叉堆 找流的中位数
    apk系统签名小技巧
    常用adb命令总结
    Android6.0 源码修改之Setting列表配置项动态添加和静态添加
    AndroidStudio开发Java工程(解决java控制台中文打印乱码+导入jar包运行工程)
    加载loading对话框的功能(不退出沉浸式效果)
    Android6.0 源码修改之屏蔽导航栏虚拟按键(Home和RecentAPP)/动态显示和隐藏NavigationBar
  • 原文地址:https://www.cnblogs.com/aquester/p/11455139.html
Copyright © 2011-2022 走看看