• redis中lua脚本实战


    redis的lua脚本说明

    lua脚本 其实是一个语言,有完整的程序控制语法和一些简单的特殊的数据结构比如table。不依赖于redis 的,但是lua脚本是c写的一个非常简单的语言,所以redis也提供了对lua的支持,而且是默认支持,以插件的方式。

    下面的说明来自知乎 https://zhuanlan.zhihu.com/p/77484377:

     一、简介

    1. Redis中为什么引入Lua脚本?
      Redis是高性能的key-value内存数据库,在部分场景下,是对关系数据库的良好补充。
      Redis提供了非常丰富的指令集,官网上提供了200多个命令。但是某些特定领域,需要扩充若干指令原子性执行时,仅使用原生命令便无法完成。
      Redis 为这样的用户场景提供了 lua 脚本支持,用户可以向服务器发送 lua 脚本来执行自定义动作,获取脚本的响应数据。Redis 服务器会单线程原子性执行 lua 脚本,保证 lua 脚本在处理的过程中不会被任意其它请求打断。
    2. Redis意识到上述问题后,在2.6版本推出了 lua 脚本功能,允许开发者使用Lua语言编写脚本传到Redis中执行。使用脚本的好处如下:
    • 减少网络开销。可以将多个请求通过脚本的形式一次发送,减少网络时延。
    • 原子操作。Redis会将整个脚本作为一个整体执行,中间不会被其他请求插入。因此在脚本运行过程中无需担心会出现竞态条件,无需使用事务。
    • 复用。客户端发送的脚本会永久存在redis中,这样其他客户端可以复用这一脚本,而不需要使用代码完成相同的逻辑。

    3. 什么是Lua?
    Lua是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放。
    其设计目的就是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。因为广泛的应用于:游戏开发、独立应用脚本、Web 应用脚本、扩展和数据库插件等。
    比如:Lua脚本用在很多游戏上,主要是Lua脚本可以嵌入到其他程序中运行,游戏升级的时候,可以直接升级脚本,而不用重新安装游戏。
    Lua脚本的基本语法可参考:菜鸟教程

    redis中调用lua 做什么呢? 一般就是利用lua 做一些稍微复杂的事情,其实就是执行lua脚本。 具体什么样的脚本呢? 通常还是执行redis 的命令, 也就是让几个redis 命令按照指顶的程序逻辑来执行。

    为什么一般都使用lua呢?因为没有更好、更简单的其他的方式。—— 难不成直接让用户执行 c语言脚本? 我觉得其实也不是不可以,但是我估计这样会非常不安全,c 的指针可是很难控制的。

    说起来有点绕,不过事实就是这样的,redis中执行lua脚本,然后lua中又调用redis命令。

    Redis中Lua的常用命令

    命令不多,就下面这几个:
    - EVAL
    - EVALSHA
    - SCRIPT LOAD - SCRIPT EXISTS
    - SCRIPT FLUSH
    - SCRIPT KILL

    eval 怎么使用? 就是直接执行lua脚本。 lua中如何调用redis命令?redis.call、或者 redis.pcall

    下面是我实验遇到的小问题以及解决方案。

    Unknown Redis command called from Lua script


    127.0.0.1:6379> EVAL "return redis.call('KEYS * ')" 0

    (error) ERR Error running script (call to f_90c305887706feea8ab72f092121aa1b4c5b043a): @user_script:1: @user_script: 1: Unknown Redis command called from Lua script

    127.0.0.1:6379>

    127.0.0.1:6379> EVAL "KEYS * " 0

    (error) ERR Error compiling script (new function): user_script:1: '=' expected near '*'

    ——似乎不支持 KEYS * 命令...

    ERR wrong number of arguments for 'eval' command

    127.0.0.1:6379> redis.call(set,hello,world)

    (error) ERR unknown command 'redis.call(set,hello,world)'

    127.0.0.1:6379> eval redis.call(set,hello,world)

    (error) ERR wrong number of arguments for 'eval' command

    127.0.0.1:6379> eval redis.call(set,hello,world) 0

    (error) ERR Error running script (call to f_317adb9b83d8b5df45f0bc67609674b0ae930a62): @enable_strict_lua:15: user_script:1: Script attempted to access unexisting global variable 'set'

    127.0.0.1:6379> eval 'redis.call("set","hello", "world")'

    (error) ERR wrong number of arguments for 'eval' command

    127.0.0.1:6379>  eval 'redis.call("set","hello", "world")' 0

    —— eval 必须要 引号, 单双都行

    127.0.0.1:6379> EVALSHA 1b936e3fe509bcbc9cd0664897bbe8fd0cac101b 0

    (error) NOSCRIPT No matching script. Please use EVAL.

    127.0.0.1:6379> SCRIPT EXISTS 1b936e3fe509bcbc9cd0664897bbe8fd0cac101b

    1) (integer) 0

    127.0.0.1:6379> SCRIPT LOAD "return 'hello'"

    "1b936e3fe509bcbc9cd0664897bbe8fd0cac101b"

    127.0.0.1:6379> SCRIPT EXISTS 1b936e3fe509bcbc9cd0664897bbe8fd0cac101b

    1) (integer) 1

    —— 返回1  是表示存在!

    Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE

    第一个窗口:127.0.0.1:6379> eval "while true do end" 0

    —— 没有响应。

    第二个窗口:127.0.0.1:6379> get hello(error) BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.127.0.0.1:6379>

    第一个窗口 关掉了, 后面的窗口还是无法执行, 一直 BUSY Redis is busy .. 只有重启redis

    why ?

    其实也可以通过script kill命令终止正在执行的脚本。如果当前执行的lua脚本对redis的数据进行了修改,比如(set)操作,那么script kill命令没办法终止脚本的运行,因为要保证lua脚本的原子性。如果执行一部分终止了,就违背了这一个原则在这种情况下,只能通过 shutdown nosave命令强行终止。

  • 相关阅读:
    Linux-diff命令
    Linux-查看文件内容命令
    Linux-tar命令
    Linux-df -h命令
    Linux-mkdir命令&touch命令
    Linux-cd命令&pwd命令
    Linux-zip命令&rz命令&sz命令
    Linux-npm install命令&脚本命令
    Linux-tail命令
    Linux-cat命令
  • 原文地址:https://www.cnblogs.com/FlyAway2013/p/16436886.html
Copyright © 2020-2023  润新知