百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

Redis进阶五之妙用Lua脚本 redis lua脚本怎么用

suiw9 2024-11-05 12:37 16 浏览 0 评论

Redis使用Lua的优势

(1) 原子操作: Redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。换句话说在编写脚本的过程中无需担心会出现竞态条件,也就无需使用事务。事务可以完成的所有功能都可以用脚本来实现。

(2) 复用: 客户端发送的脚本会永久存储在Redis中,这就意味着其他客户端(可以是其他语言开发的项目)可以复用这一脚本而不需要使用代码完成同样的逻辑。

(3) 速度快:见 与其它语言的性能比较, 还有一个 JIT编译器可以显著地提高多数任务的性能; 对于那些仍然对性能不满意的人, 可以把关键部分使用C实现, 然后与其集成, 这样还可以享受其它方面的好处。

Redis Lua脚本的应用场景

(1)复杂查询:对于一些复杂的查询需求,使用Lua脚本可以快速地实现,避免了在客户端进行数据处理的麻烦。

(2)计算逻辑:对于一些需要进行计算逻辑的场景,即使在Redis中没有提供相应的计算命令,也可以通过Lua脚本实现自定义的计算逻辑。

(3)事务操作:Lua脚本可以保证一组Redis命令的原子性,这使得在Redis上实现事务操作成为可能。

(4)实时统计:Lua脚本可以实时统计Redis中的数据,例如计算实时UV、PV等数据。

Lua简述

Lua 语言是在1993年由巴西一个大学研究小组发明,其设计目标是作为嵌入式程序移植到其他应用程序,它是由C语言实现的,虽然简单小巧但是功能强大,所以许多应用程序都选用它作为脚本语言,尤其是在游戏领域,例如大名鼎鼎的暴雪公司将Lua语言引入到“魔兽世界“这款游戏中,Rovio公司将Lua语言作为“愤怒的小鸟”这款火爆游戏的关卡升级引擎,Web服务器Nginx将Lua语言作为扩展,增强自身功能。Redis将Lua作为脚本语言可帮助开发者定制自己的Redis命令,在这之前,必须修改源代码。在介绍如何在Redis中使用Lua脚本之前,有必要对Lua语言的使用做一个基本介绍。

工欲善其事,必先利其器,我们先介绍 Lua 环境安装 和 简单使用。

Lua 环境安装

Linux 系统上安装

Linux & Mac上安装 Lua 非常简单,只需要下载源码包并在终端解压编译即可,本文使用了5.3.0版本进行安装:

curl -R -O http://www.lua.org/ftp/lua-5.3.0.tar.gz
tar zxf lua-5.3.0.tar.gz
cd lua-5.3.0
make linux test
make install

Mac OS X 系统上安装

curl -R -O http://www.lua.org/ftp/lua-5.3.0.tar.gz
tar zxf lua-5.3.0.tar.gz
cd lua-5.3.0
make macosx test
make install

安装参考

$ cd lua-5.3.0
$ ls
Makefile	README		doc		src
$ make macosx test
cd src && /Library/Developer/CommandLineTools/usr/bin/make macosx
/Library/Developer/CommandLineTools/usr/bin/make all SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline" CC=cc
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lapi.o lapi.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lcode.o lcode.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lctype.o lctype.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o ldebug.o ldebug.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o ldo.o ldo.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o ldump.o ldump.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lfunc.o lfunc.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lgc.o lgc.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o llex.o llex.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lmem.o lmem.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lobject.o lobject.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lopcodes.o lopcodes.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lparser.o lparser.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lstate.o lstate.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lstring.o lstring.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o ltable.o ltable.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o ltm.o ltm.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lundump.o lundump.c
lundump.c:233:33: warning: adding 'int' to a string does not append to the string [-Wstring-plus-int]
  checkliteral(S, LUA_SIGNATURE + 1, "not a");  /* 1st char already checked */
                  ~~~~~~~~~~~~~~^~~
lundump.c:233:33: note: use array indexing to silence this warning
  checkliteral(S, LUA_SIGNATURE + 1, "not a");  /* 1st char already checked */
                                ^
                  &             [  ]
1 warning generated.
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lvm.o lvm.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lzio.o lzio.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lauxlib.o lauxlib.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lbaselib.o lbaselib.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lbitlib.o lbitlib.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lcorolib.o lcorolib.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o ldblib.o ldblib.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o liolib.o liolib.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lmathlib.o lmathlib.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o loslib.o loslib.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lstrlib.o lstrlib.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o ltablib.o ltablib.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lutf8lib.o lutf8lib.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o loadlib.o loadlib.c
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o linit.o linit.c
ar rcu liblua.a lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o lauxlib.o lbaselib.o lbitlib.o lcorolib.o ldblib.o liolib.o lmathlib.o loslib.o lstrlib.o ltablib.o lutf8lib.o loadlib.o linit.o 
ranlib liblua.a
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o lua.o lua.c
cc -o lua   lua.o liblua.a -lm -lreadline 
cc -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX    -c -o luac.o luac.c
cc -o luac   luac.o liblua.a -lm -lreadline 
src/lua -v
Lua 5.3.0  Copyright (C) 1994-2015 Lua.org, PUC-Rio

$ make install
cd src && mkdir -p /usr/local/bin /usr/local/include /usr/local/lib /usr/local/man/man1 /usr/local/share/lua/5.3 /usr/local/lib/lua/5.3
mkdir: /usr/local/include: Permission denied
mkdir: /usr/local/man/man1: Permission denied
mkdir: /usr/local/share/lua/5.3: Permission denied
mkdir: /usr/local/lib/lua/5.3: Permission denied
make: *** [install] Error 1
a123456@luludeMBP-2 lua-5.3.0 % sudo make install
Password:
cd src && mkdir -p /usr/local/bin /usr/local/include /usr/local/lib /usr/local/man/man1 /usr/local/share/lua/5.3 /usr/local/lib/lua/5.3
cd src && install -p -m 0755 lua luac /usr/local/bin
cd src && install -p -m 0644 lua.h luaconf.h lualib.h lauxlib.h lua.hpp /usr/local/include
cd src && install -p -m 0644 liblua.a /usr/local/lib
cd doc && install -p -m 0644 lua.1 luac.1 /usr/local/man/man1

入门案例

接下来我们创建一个 HelloWorld.lua 文件,代码如下:

print("Hello World!")

执行以下命令:

$ lua HelloWorld.lua

输出结果为:

Hello World!

数据类型及其逻辑处理

Lua 语言提供了如下几种数据类型:booleans 布尔,numbers 数值,strings 字符串,tables 表格,和许多高级语言相比,相对简单。下面将结合例子对Lua的基本数据类型和逻辑处理进行说明。

字符串

下面定义一个字符串类型的数据:

local string val = "world"

其中local 代表 val 是一个局部变量,如果没有loacl 代表是全局变量。print 函数可以打印出变量的值,例如下面代码将打印 world , 其中 "--" 是Lua语言的注释。

print(val) --结果是 "world"

Lua 语言详细学习,请参考:「链接」

Redis Lua执行流程图

Redis eval 命令

Redis eval 命令使用 Lua 解释器执行脚本。

语法

eval 脚本内容 key个数 key列表 参数列表

redis 127.0.0.1:6379> EVAL script numkeys key [key ...] arg [arg ...] 

参数说明:

script: 参数是一段 Lua 脚本程序。脚本不必(也不应该)定义为一个 Lua 函数。

numkeys: 用于指定键名参数的个数。

key [key ...]: 从 EVAL 的第三个参数开始算起,表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2] ,以此类推)。

arg [arg ...]: 附加参数,在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1] 、 ARGV[2] ,诸如此类)。

实例

127.0.0.1:6379> 
127.0.0.1:6379> eval "return redis.call('set',KEYS[1],KEYS[2])" 2 name yyp
OK
127.0.0.1:6379> eval "return redis.call('get',KEYS[1])" 1 name
"yyp"
127.0.0.1:6379> 

eval 执行流程

Redis evalsha 命令

除了使用eval,Redis 还提供了 evalsha 命令来执行 Lua 脚本。首先要将Lua 脚本加载到Redis 服务器,得到该脚本的SHA1 效验和,evalsha 命令使用 SHA1 作为参数可以直接执行对应的Lua脚本,避免每次发送Lua脚本的开销。这样客户端就不需要每次执行脚本内容,而脚本也会常驻在服务端,脚本功能得到了复用。

加载脚本:script load 命令可以将脚本内容加载到Redis内存中,例如下面将lua_get.lua加载到Redis中,得到SHA1为 "52da8c7de39385e305fb1af2a8ffd21534af996f"。

lua_get.lua脚本内容

return redis.call('get','name')

script load 命令执行

$ ./redis-cli -p 6379 script load "$(cat lua_get.lua)"
"52da8c7de39385e305fb1af2a8ffd21534af996f"
$

执行脚本:evalsha 的使用方法如下,参数使用 SHA1 值,执行逻辑和eval一致。

语法

evalsha 脚本sha1值 key个数 key列表 参数列表

实例

127.0.0.1:6379> evalsha 52da8c7de39385e305fb1af2a8ffd21534af996f 0
"yyp"
127.0.0.1:6379>

evalsha 执行流程

Lua的Redis API

Lua可以使用redis.call 函数实现对 Redis 的访问,例如下面代码Lua使用 redis.call调用了 Redis的 set 和 get 操作。

redis.call("set","hello","world")
redis.call("get","hell0"

放在 Redis 的执行效果如下:

127.0.0.1:6379> eval "return redis.call('set',KEYS[1],KEYS[2])" 2 hello world
OK
127.0.0.1:6379> eval "return redis.call('get',KEYS[1])" 1 hello
"world"
127.0.0.1:6379> 

除此之外 Lua 还可以使用 redis.pcall 函数实现对 Redis 的调用,redis.call 和 redis.pcall 的不同在于,如果 redis.call 执行失败,那么脚本执行结果会直接返回错误,而redis.pcall 会忽略错误继续执行脚本,所以在实际开发中要根据具体的应用场景进行函数的选择。

相关推荐

俄罗斯的 HTTPS 也要被废了?(俄罗斯网站关闭)

发布该推文的ScottHelme是一名黑客,SecurityHeaders和ReportUri的创始人、Pluralsight作者、BBC常驻黑客。他表示,CAs现在似乎正在停止为俄罗斯域名颁发...

如何强制所有流量使用 HTTPS一网上用户

如何强制所有流量使用HTTPS一网上用户使用.htaccess强制流量到https的最常见方法可能是使用.htaccess重定向请求。.htaccess是一个简单的文本文件,简称为“.h...

https和http的区别(https和http有何区别)

“HTTPS和HTTP都是数据传输的应用层协议,区别在于HTTPS比HTTP安全”。区别在哪里,我们接着往下看:...

快码住!带你十分钟搞懂HTTP与HTTPS协议及请求的区别

什么是协议?网络协议是计算机之间为了实现网络通信从而达成的一种“约定”或“规则”,正是因为这个“规则”的存在,不同厂商的生产设备、及不同操作系统组成的计算机之间,才可以实现通信。简单来说,计算机与网络...

简述HTTPS工作原理(简述https原理,以及与http的区别)

https是在http协议的基础上加了一层SSL(由网景公司开发),加密由ssl实现,它的目的是为用户提供对网站服务器的身份认证(需要CA),以至于保护交换数据的隐私和完整性,原理如图示。1、客户端发...

21、HTTPS 有几次握手和挥手?HTTPS 的原理什么是(高薪 常问)

HTTPS是3次握手和4次挥手,和HTTP是一样的。HTTPS的原理...

一次安全可靠的通信——HTTPS原理

为什么HTTPS协议就比HTTP安全呢?一次安全可靠的通信应该包含什么东西呢,这篇文章我会尝试讲清楚这些细节。Alice与Bob的通信...

为什么有的网站没有使用https(为什么有的网站点不开)

有的网站没有使用HTTPS的原因可能涉及多个方面,以下是.com、.top域名的一些见解:服务器性能限制:HTTPS使用公钥加密和私钥解密技术,这要求服务器具备足够的计算能力来处理加解密操作。如果服务...

HTTPS是什么?加密原理和证书。SSL/TLS握手过程

秘钥的产生过程非对称加密...

图解HTTPS「转」(图解http 完整版 彩色版 pdf)

我们都知道HTTPS能够加密信息,以免敏感信息被第三方获取。所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTPS协议。...

HTTP 和 HTTPS 有何不同?一文带你全面了解

随着互联网时代的高速发展,Web服务器和客户端之间的安全通信需求也越来越高。HTTP和HTTPS是两种广泛使用的Web通信协议。本文将介绍HTTP和HTTPS的区别,并探讨为什么HTTPS已成为We...

HTTP与HTTPS的区别,详细介绍(http与https有什么区别)

HTTP与HTTPS介绍超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的...

一文让你轻松掌握 HTTPS(https详解)

一文让你轻松掌握HTTPS原文作者:UC国际研发泽原写在最前:欢迎你来到“UC国际技术”公众号,我们将为大家提供与客户端、服务端、算法、测试、数据、前端等相关的高质量技术文章,不限于原创与翻译。...

如何在Spring Boot应用程序上启用HTTPS?

HTTPS是HTTP的安全版本,旨在提供传输层安全性(TLS)[安全套接字层(SSL)的后继产品],这是地址栏中的挂锁图标,用于在Web服务器和浏览器之间建立加密连接。HTTPS加密每个数据包以安全方...

一文彻底搞明白Http以及Https(http0)

早期以信息发布为主的Web1.0时代,HTTP已可以满足绝大部分需要。证书费用、服务器的计算资源都比较昂贵,作为HTTP安全扩展的HTTPS,通常只应用在登录、交易等少数环境中。但随着越来越多的重要...

取消回复欢迎 发表评论: