网站建设的工期拖延如何解决,台州网站建设哪家公司好,ts小说wordpress,seo搜索排名优化方法对别人的意见要表示尊重。千万别说#xff1a;你错了。——卡耐基Lua 是一种轻量小巧的脚本语言#xff0c;用标准 C 语言编写并以源代码形式开放#xff0c;其设计目的是为了嵌入应用程序中#xff0c;从而为应用程序提供灵活的扩展和定制功能。由于 Lua 语言… 对别人的意见要表示尊重。千万别说你错了。——卡耐基Lua 是一种轻量小巧的脚本语言用标准 C 语言编写并以源代码形式开放其设计目的是为了嵌入应用程序中从而为应用程序提供灵活的扩展和定制功能。由于 Lua 语言具备原子性其在执行的过程中不会被其它程序打断对于并发下数据的一致性是有帮助的。作者简介五月君Nodejs Developer慕课网认证作者热爱技术、喜欢分享的 90 后青年欢迎关注 Nodejs技术栈 和 Github 开源项目 https://www.nodejs.redRedis 的两种 Lua 脚本Redis 支持两种运行 Lua 脚本的方式一种是直接在 Redis 中输入 Lua 代码适合于一些简单的脚本。另一种方式是编写 Lua 脚本文件适合于有逻辑运算的情况Redis 使用 SHA1 算法支持对脚本签名和 Script Load 预先缓存需要运行的时候通过签名返回的标识符即可。下面会分别介绍如何应用 Redis 提供的 EVAL、EVALSHA 两个命令来实现对 Lua 脚本的应用同时介绍一些在 Node.js 中该如何去应用 Redis 的 Lua 脚本。EVALRedis 2.6.0 版本开始通过内置的 Lua 解释器可以使用 EVAL 命令对 Lua 脚本进行求值script执行的脚本numkeys指定键名参数个数key键名可以多个(key1、key2)通过 KEYS[1] KEYS[2] 的形式访问atg键值可以多个(val1、val2)通过 ARGS[1] ARGS[2] 的形式访问EVAL script numkeys key [key ...] arg [arg ...]EVAL Redis 控制台实践按照上面命令格式写一个实例如下通过 KEYS[] 数组的形式访问 ARGV[]这里下标是以 1 开始KEYS[1] 对应的键名为 name1ARGV[2] 对应的值为 val2127.0.0.1:6379 EVAL return redis.call(SET, KEYS[1], ARGV[2]) 2 name1 name2 val1 val2OK执行以上命令通过 get 查看 name1 对应的值为 val2127.0.0.1:6379 get name1val2注意以上命令如果不使用 return 将会返回 (nil)127.0.0.1:6379 EVAL redis.call(SET, KEYS[1], ARGV[2]) 2 name1 name2 val1 val2(nil)redis.call VS redis.pcallredis.call 和 redis.pcall 是两个不同的 Lua 函数来调用 redis 命令两个命令很类似区别是如果 redis 命令中出现错误异常redis.call 会直接返回一个错误信息给调用者而 redis.pcall 会以 Lua 的形式对错误进行捕获并返回。使用 redis.call这里执行了两条 Redis 命令第一条故意写了一个 SET_ 这是一个错误的命令可以看到出错后错误信息被抛出给了调用者同时你执行 get name2 会得到 (nil)第二条命令也没有被执行127.0.0.1:6379 EVAL redis.call(SET_, KEYS[1], ARGV[2]); redis.call(SET, KEYS[2], ARGV[3]) 2 name1 name2 val1 val2 val3(error) ERR Error running script (call to f_bf814e38e3d98242ae0c62791fa299f04e757a7d): user_script:1: user_script: 1: Unknown Redis command called from Lua script使用 redis.pcall和上面同样的操作使用 redis.pcall 可以看到输出结果为 (nil) 它的错误被 Lua 捕获了这时我们在执行 get name2 会得到一个设置好的结果 val3这里第二条命令是被执行了的。EVAL redis.pcall(SET_, KEYS[1], ARGV[2]); redis.pcall(SET, KEYS[2], ARGV[3]) 2 name1 name2 val1 val2 val3(nil)EVAL 在 Node.js 中实现ioredis 支持所有的脚本命令比如 EVAL、EVALSHA 和 SCRIPT。但是在现实场景中使用它是很繁琐的因为开发人员必须注意脚本缓存并检测何时使用 EVAL何时使用 EVALSHA。ioredis 公开了一个 defineCommand 方法使脚本更容易使用。const Redis require(ioredis);const redis new Redis(6379, 127.0.0.1);const evalScript return redis.call(SET, KEYS[1], ARGV[2]);redis.defineCommand(evalTest, {numberOfKeys: 2,lua: evalScript,})async function eval() {await redis.evalTest(name1, name2, val1, val2);const result await redis.get(name1);console.log(result); // val2}eval();EVALSHAEVAL 命令要求你在每次执行脚本的时候都发送一次脚本主体 (script body)。Redis 有一个内部的缓存机制因此它不会每次都重新编译脚本通过 EVALSHA 来实现根据给定的 SHA1 校验码对缓存在服务器中的脚本进行求值。SHA1 怎么生成呢通过 script 命令可以对脚本缓存进行操作SCRIPT FLUSH清除所有脚本缓存SCRIPT EXISTS检查指定的脚本是否存在于脚本缓存SCRIPT LOAD将一个脚本装入脚本缓存但并不立即运行它SCRIPT KILL杀死当前正在运行的脚本EVALSHA 命令格式同上面 EVAL 不同的是前面 EVAL script 换成了 EVALSHA sha1EVALSHA sha1 numkeys key [key ...] arg [arg ...]EVALSHA Redis 控制台实践载入脚本缓存127.0.0.1:6379 SCRIPT LOAD redis.pcall(SET, KEYS[1], ARGV[2]);2a3b189808b36be907e26dab7ddcd8428dcd1bc8以上脚本执行之后会返回一个 SHA-1 签名过后的标识字符串这个字符串用于下面命令执行签名之后的脚本127.0.0.1:6379 EVALSHA 2a3b189808b36be907e26dab7ddcd8428dcd1bc8 2 name1 name2 val1 val2进行 get 操作读取 name1 的只为 val2127.0.0.1:6379 get name1val2EVALSHA 在 Node.js 中实现分为三步缓存脚本、执行脚本、获取数据const Redis require(ioredis);const redis new Redis(6379, 127.0.0.1);const evalScript return redis.call(SET, KEYS[1], ARGV[2]);async function evalSHA() {// 1. 缓存脚本获取 sha1 值const sha1 await redis.script(load, evalScript);console.log(sha1); // 6bce4ade07396ba3eb2d98e461167563a868c661// 2. 通过 evalsha 执行脚本await redis.evalsha(sha1, 2, name1, name2, val1, val2);// 3. 获取数据const result await redis.get(name1);console.log(result); // val2}evalSHA();Lua 脚本文件有逻辑运算的脚本可以编写 Lua 脚本文件编写一些简单的脚本也不难可以参考这个教程 https://www.runoob.com/lua/lua-tutorial.htmlLua 文件以下是一个测试代码通过读取两个值比较返回不同的值通过 Lua 脚本实现后可以多条 Redis 命令的原子性。-- test.lua-- 先 SETredis.call(SET, KEYS[1], ARGV[1])redis.call(SET, KEYS[2], ARGV[2])-- GET 取值local key1 tonumber(redis.call(GET, KEYS[1]))local key2 tonumber(redis.call(GET, KEYS[2]))-- 如果 key1 小于 key2 返回 0-- nil 相当于 falseif (key1 nil or key2 nil or key1 key2)then return 0else return 1endNode.js 中加载 Lua 脚本文件和上面 Node.js 中应用 Lua 差别不大多了一步通过 fs 模块先读取 Lua 脚本文件在通过 eval 或者 evalsha 执行。const Redis require(ioredis);const redis new Redis(6379, 127.0.0.1);const fs require(fs);async function test() {const redisLuaScript fs.readFileSync(./test.lua);const result1 await redis.eval(redisLuaScript, 2, name1, name2, 20, 10);const result2 await redis.eval(redisLuaScript, 2, name1, name2, 10, 20);console.log(result1, result2); // 1 0}test();▼往期精彩回顾▼入门 Node.js Net 模块构建 TCP 网络服务Node.js 核心模块都在使用的 Events 模块你了解吗消息中间件 RabbitMQ 入门篇重磅 | OpenJS 基金会推出 Node.js 专业认证考试分享 10 道 Nodejs EventLoop 和事件相关面试题Docker 容器环境下 Node.js 应用程序的优雅退出Node.js 服务 Docker 容器化应用实践Node.js 是什么我为什么选择它分享 10 道 Nodejs 进程相关面试题Node.js进阶之进程与线程Node.js 中的缓冲区(Buffer)究竟是什么Node.js 内存管理和 V8 垃圾回收机制浅谈 Node.js 模块机制及常见面试问题解答在看点这里