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

Redis进阶五之妙用Lua脚本(redis-lua)

mhr18 2024-10-26 10:52 23 浏览 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 会忽略错误继续执行脚本,所以在实际开发中要根据具体的应用场景进行函数的选择。

相关推荐

B站收藏视频失效?mybili 收藏夹备份神器完整部署指南

本内容来源于@什么值得买APP,观点仅代表作者本人|作者:羊刀仙很多B站用户都有过类似经历:自己精心收藏的视频突然“消失”,点开一看不是“已被删除”,就是“因UP主设置不可见”。而B站并不会主动通知...

中间件推荐初始化配置

Redis推荐初始化配置bind0.0.0.0protected-modeyesport6379tcp-backlog511timeout300tcp-keepalive300...

Redis中缓存穿透问题与解决方法

缓存穿透问题概述在Redis作为缓存使用时,缓存穿透是常见问题。正常查询流程是先从Redis缓存获取数据,若有则直接使用;若没有则去数据库查询,查到后存入缓存。但当请求的数据在缓存和数据库中都...

后端开发必看!Redis 哨兵机制如何保障系统高可用?

你是否曾在项目中遇到过Redis主服务器突然宕机,导致整个业务系统出现数据读取异常、响应延迟甚至服务中断的情况?面对这样的突发状况,作为互联网大厂的后端开发人员,如何快速恢复服务、保障系统的高可用...

Redis合集-大Key处理建议

以下是Redis大Key问题的全流程解决方案,涵盖检测、处理、优化及预防策略,结合代码示例和最佳实践:一、大Key的定义与风险1.大Key判定标准数据类型大Key阈值风险场景S...

深入解析跳跃表:Redis里的"老六"数据结构,专治各种不服

大家好,我是你们的码农段子手,今天要给大家讲一个Redis世界里最会"跳科目三"的数据结构——跳跃表(SkipList)。这货表面上是个青铜,实际上是个王者,连红黑树见了都要喊声大哥。...

Redis 中 AOF 持久化技术原理全解析,看完你就懂了!

你在使用Redis的过程中,有没有担心过数据丢失的问题?尤其是在服务器突然宕机、意外断电等情况发生时,那些还没来得及持久化的数据,是不是让你夜不能寐?别担心,Redis的AOF持久化技术就是...

Redis合集-必备的几款运维工具

Redis在应用Redis时,经常会面临的运维工作,包括Redis的运行状态监控,数据迁移,主从集群、切片集群的部署和运维。接下来,从这三个方面,介绍一些工具。先来学习下监控Redis实时...

别再纠结线程池大小 + 线程数量了,没有固定公式的!

我们在百度上能很轻易地搜索到以下线程池设置大小的理论:在一台服务器上我们按照以下设置CPU密集型的程序-核心数+1I/O密集型的程序-核心数*2你不会真的按照这个理论来设置线程池的...

网络编程—IO多路复用详解

假如你想了解IO多路复用,那本文或许可以帮助你本文的最大目的就是想要把select、epoll在执行过程中干了什么叙述出来,所以具体的代码不会涉及,毕竟不同语言的接口有所区别。基础知识IO多路复用涉及...

5分钟学会C/C++多线程编程进程和线程

前言对线程有基本的理解简单的C++面向过程编程能力创造单个简单的线程。创造单个带参数的线程。如何等待线程结束。创造多个线程,并使用互斥量来防止资源抢占。会使用之后,直接跳到“汇总”,复制模板来用就行...

尽情阅读,技术进阶,详解mmap的原理

1.一句话概括mmapmmap的作用,在应用这一层,是让你把文件的某一段,当作内存一样来访问。将文件映射到物理内存,将进程虚拟空间映射到那块内存。这样,进程不仅能像访问内存一样读写文件,多个进程...

C++11多线程知识点总结

一、多线程的基本概念1、进程与线程的区别和联系进程:进程是一个动态的过程,是一个活动的实体。简单来说,一个应用程序的运行就可以被看做是一个进程;线程:是运行中的实际的任务执行者。可以说,进程中包含了多...

微服务高可用的2个关键技巧,你一定用得上

概述上一篇文章讲了一个朋友公司使用SpringCloud架构遇到问题的一个真实案例,虽然不是什么大的技术问题,但如果对一些东西理解的不深刻,还真会犯一些错误。这篇文章我们来聊聊在微服务架构中,到底如...

Java线程间如何共享与传递数据

1、背景在日常SpringBoot应用或者Java应用开发中,使用多线程编程有很多好处,比如可以同时处理多个任务,提高程序的并发性;可以充分利用计算机的多核处理器,使得程序能够更好地利用计算机的资源,...

取消回复欢迎 发表评论: