网站首页 > 精选教程 正文
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 会忽略错误继续执行脚本,所以在实际开发中要根据具体的应用场景进行函数的选择。
猜你喜欢
- 2024-10-04 Java并发:分布式应用限流 Redis + Lua 实践
- 2024-10-04 OpenResty(一)Lua openresty lua脚本灰度发布
- 2024-10-04 运维篇—基于Nginx+Lua实现的灰度发布
- 2024-10-04 Nginx与LUA(4) nginx lua优缺点
- 2024-10-04 高并发限流技术分析及实践 高并发限流方案
- 2024-10-04 Redis弱事务性与Lua脚本原子性分析
- 2024-10-04 像调试java一样来调试Redis lua redis调试工具
- 2024-10-04 Nginx与LUA(3) nginx与uwsgi详解
- 2024-10-04 企业级电商网站使用Nginx+Lua(OpenResty)实现高性能Web应用
- 2024-10-04 Lua 基础入门 lua语言零基础教程视频
你 发表评论:
欢迎- 最近发表
-
- 我的世界光影MOD下载(我的世界光影mod下载安装)
- 我的世界1.7/1.8VoxelMap小地图MOD下载
- 我的世界1.7.10多世界 整合包(我的世界1.7.10forge整合包)
- 我的世界1.8最好用的修改器下载(我的世界1.8最好用的修改器下载安装)
- 我的世界更多弯曲动作MOD下载(我的世界更多弯曲动作mod下载手机版)
- 我的世界龙珠MOD下载(我的世界龙珠模组整合包下载)
- 我的世界1.7.10以太2 下载(我的世界以太2mod1.12.2)
- 我的世界虚拟人生MOD下载分享(我的世界虚拟人生下载安装)
- 我的世界无正版账号的简单联机方法(非网易版,仅适用于局域网)
- “我的语言极限,即是我的世界的极限。” ——《On Java》书籍推荐
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)