Redis 7.0 新功能 Redis Functions 介绍

背景

2022年4月27日,Redis正式发布了7.0更新(其实早在2022年1月31日,Redis已经预发布了7.0rc-1,经过社区的考验后,确认没重大Bug才会正式发布)。

在众多新特性中,Redis团队把Redis Functions放在了第一位:

image.png

可见官方对这个特性是相当重视。今天我们来一起学习下Redis Functions

学习前,需了解:Redis旧版本中的lua脚本

Redis为了给开发者更灵活的能力,内置了lua解释器,可以让开发者执行功能强大的「原子操作」。

例如以下场景,只通过Redis本身的数据结构,实现起来是比较低效的:

  • 某个key的string value自乘2。
  • 若keyA=某个数字,则同时设置keyA和keyB。
  • ……

由于Redis本身并没有暴露上述命令,所以我们需要通过transactions或者watch来实现,而watch又不能保证100%成功,可能还需要引入重试。也可以通过分布式锁来实现。但这些都让系统变得更复杂、效率更低。

最高效的方式,其实是Redis内部实现好,暴露相关指令出来(例如incr指令),因为指令是原子的,所以可以放心使用。当然Redis即使暴露再多指令也没用,肯定无法覆盖各种复杂的实际场景,所以最好的方式就是提供编程能力,允许用户自定义「原子操作」,就是通过lua脚本实现。

有个命令是EVAL

EVAL script numkeys [key [key ...]] [arg [arg ...]]

就可以执行一段lua脚本。例如可以这样用:

> EVAL "return ARGV[1]" 0 hello
"hello"

在lua中,Redis提供了Redis的几乎所有命令API,你可以读取key、设置key等。在执行lua过程中,Redis不会打断,只有执行完毕,才会去执行其它命令。也就是说,这段脚本是「原子操作」。

但是这种方式有些问题:

  1. 每次执行脚本时,需要先编译再执行,效率低(当然Redis也会针对脚本计算哈希,把编译结果存下来,如果后面的脚本跟之前一致,就不再编译了,直接取之前的结果)。但是第一次执行时,依然存在效率问题,尤其是Redis刚启动时,或者脚本初次执行时。
  2. lua脚本复用比较困难,因为每次都要加载一段新的脚本,函数复用成本较高。

所以,我们继续看看Redis Functions是怎么解决这些问题的。

Redis Functions 相关指令介绍

首先我们先看看Redis Functions提供了哪些指令。

了解Redis Functions必须知道的指令

为了了解这个Redis Functions功能,你至少需要知道这2条:

  • Function Load
  • FCALL

Function Load

先看个例子

首先你可以新建一个lua脚本,名字叫hello.lua:

#!lua name=mylib

redis.register_function('myfunc', function(keys, args) return args[1] end)

注意上面的redis.register_function方法,是必须的,就是通过该API(Redis给lua提供的API),来注册函数到Redis中,2个参数分别是函数名称、函数引用。

然后可以执行下面这个shell脚本(前提是你已经安装了redis、redis-cli,并启动了redis):

cat mylib.lua | redis-cli -x FUNCTION LOAD

这样,就给redis注册了一个名叫mylib的库,这个库里注册了一个叫myfunc的函数。函数作用是直接return参数1。

也可在redis-cli中直接注册

当然,你也可以直接在redis-cli中调用FUNCTION LOAD注册:

FUNCTION LOAD "#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return args[1] end)"

解释 FUNCTION LOAD

语法:

FUNCTION LOAD [REPLACE] function-code

你可以使用该语句加载一个lua模块到redis中,一个模块包含一个或多个函数。后续在redis可以调用这些函数。有如下特性:

  • lua代码需要编译,在FUNCTION LOAD后会自动编译,以后每次调用时都不需要编译,调用速度都是快的。(也许你知道Redis有EVAL,它可以直接执行一段lua代码,但它第一次执行时需要编译,所以初次调用速度不如先FUNCTION LOAD再调用)
  • 支持模块级别的重新加载。只要增加个参数REPLACE,就可以用新模块替换同名旧模块(若该模块是第一次加载,也会加载成功的)。
  • Redis重要特性之一是内存数据可持久化保存。当你加载函数后,关闭Redis时,注册的函数也会被持久化到硬盘。重启Redis时自动重新加载之前加载的函数。
  • Redis Function中执行代码是原子操作,执行过程中不会被打断。

注册完毕了,必然要执行,怎么执行呢,就是用FCALL

FCALL

FCALL myfunc 0 hahahahaha

指定了函数名,hahahahaha就是参数1。0我们之后再介绍。

这样执行后,不出意外,会输出hahahahaha

image.png

解释FCALL

语法:

FCALL function numkeys [key [key ...]] [arg [arg ...]]

function就是函数名,就是你的lua文件中,redis.register_function的第一个参数。

numkeys是指后面的参数中代表Redis Key的参数有多少个。

后面可以跟一系列参数,参数有2种:代表Redis key的参数、其它参数。

也就是说,如果你要在lua函数中访问Redis的key,必须通过参数传进来,千万不要自己去拼接。 自己拼接key参数在单机Redis没问题,但是分布式Redis中会有大问题。分布式Redis需要知道你在这个「原子操作」中可能读/写哪些key,来做一些并发控制,以免读到脏数据。

其它指令

  • FCALL_RO: 只读模式调用函数(意思是在函数执行时,你无法写入Redis数据,但可以读取)。分布式Redis针对这种模式会有优化。
  • FUNCTION DELETE: 删除加载的lua模块(注意是模块维度删除)。
  • FUNCTION DUMP: 序列化已加载的函数,返回byte串。
  • FUNCTION RESTORE: 通过byte串(恢复)加载函数。有3种模式:FLUSH(清空已加载的再恢复)、APPEND(新增,但是同名的不再加载)、REPLACE(新增,并替代同名)。
  • FUNCTION FLUSH: 清空已加载函数。
  • FUNCTION KILL: 该命令可以终止正在执行的只读的函数。
  • FUNCTION LIST: 返回已加载的模块、函数列表。
  • FUNCTION STATS: 获取正在执行的函数的状态(函数名、参数信息、已经执行了多久)。因为有些函数耗时太久,会导致Redis这个单线程一直卡着,所以通过查询状态,用户可以决策是否通过FUNCTION KILL终止它。

写在最后

推荐阅读官方文档:https://redis.io/docs/manual/programmability/functions-intro/

我是HullQin,公众号线下聚会游戏的作者(欢迎关注我,交个朋友)。转发本文前需获得作者HullQin授权。我独立开发了《联机桌游合集》,是个网页,可以很方便的跟朋友联机玩斗地主、五子棋等游戏,不收费无广告。还开发了《Dice Crush》参加Game Jam 2022。喜欢可以关注我噢~我有空了会分享做游戏的相关技术,会在这个专栏里分享:《教你做小游戏》

原文地址:https://cloud.tencent.com/developer/article/2128596

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340