What's New in Redis 7.0 What are Redis Functions?An artifact that can easily implement "complex atomic operations"!

HullQin 2022-09-23 08:50:09 阅读数:31

newredisredisfunctionsartifact

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情.

背景

2022年4月27日,Redis正式发布了7.0更新(其实早在2022年1月31日,RedisIt has been pre-released7.0rc-1,After being tested by the community,Make sure it doesn't matterBug才会正式发布).

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

image.png

It can be seen that the official attaches great importance to this feature.今天我们来一起学习下Redis Functions.

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

RedisIn order to give developers more flexibility,内置了lua解释器,Allows developers to perform powerful functions「原子操作」.

例如以下场景,只通过Redis本身的数据结构,It is relatively inefficient to implement:

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

由于RedisThe above command is not exposed by itself,所以我们需要通过transactions或者watch来实现,而watch又不能保证100%成功,It may also be necessary to introduce retries.也可以通过分布式锁来实现.But these all make the system more complicated、效率更低.

最高效的方式,其实是Redis内部实现好,Expose relevant instructions(例如incr指令),Because instructions are atomic,所以可以放心使用.当然RedisEven exposing more instructions is useless,Certainly cannot cover a variety of complex real-world scenarios,So the best way is to provide programming ability,允许用户自定义「原子操作」,就是通过lua脚本实现.

有个命令是EVAL

EVAL script numkeys [key [key ...]] [arg [arg ...]]
复制代码

can execute a sectionlua脚本.例如可以这样用:

> EVAL "return ARGV[1]" 0 hello
"hello"
复制代码

在lua中,Redis提供了Redisalmost all commandsAPI,你可以读取key、设置key等.在执行lua过程中,Redis不会打断,Only executed,to execute other commands.也就是说,This script is「原子操作」.

But there are some problems with this way:

  1. 每次执行脚本时,需要先编译再执行,效率低(当然RedisHash is also calculated for scripts,Save the compilation result,If the following script is the same as before,will no longer compile,Take the previous result directly).But when executed for the first time,There are still efficiency issues,尤其是Redis刚启动时,Or when the script is first executed.
  2. luaScript reuse is difficult,Because every time a new script is loaded,The cost of function reuse is high.

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

Redis Functions 相关指令介绍

首先我们先看看Redis FunctionsWhat instructions are provided.

了解Redis FunctionsMust-know instructions

为了了解这个Redis Functions功能,You at least need to know this2条:

  • Function Load
  • FCALL

Function Load

先看个例子

First you can create a new onelua脚本,名字叫hello.lua:

#!lua name=mylib
redis.register_function('myfunc', function(keys, args) return args[1] end)
复制代码

注意上面的redis.register_function方法,是必须的,就是通过该API(Redis给lua提供的API),to register the function toRedis中,2The parameters are the function names、函数引用.

Then you can do the followingshell脚本(前提是你已经安装了redis、redis-cli,并启动了redis):

cat mylib.lua | redis-cli -x FUNCTION LOAD
复制代码

这样,就给redisregistered a namemylib的库,This Curry registered a callmyfunc的函数.Function action is directreturn参数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
复制代码

You can use this statement to load onelua模块到redis中,A module contains one or more functions.后续在redis可以调用这些函数.有如下特性:

  • lua代码需要编译,在FUNCTION LOADIt will be automatically compiled after,Compilation is not required for each subsequent call,The call speed is fast.(也许你知道Redis有EVAL,It can directly execute a sectionlua代码,But it needs to be compiled the first time it is executed,So the first call is not as fast as the firstFUNCTION LOAD再调用)
  • 支持Module level reloading.Just add a parameterREPLACE,You can replace the old module with the same name with the new module(If the module is loaded for the first time,will also load successfully).
  • RedisOne of the important features is in-memory dataPersistent storage.after you load the function,关闭Redis时,Registered functions are also persisted to disk.重启RedisWhen automatically reloading previously loaded functions.
  • Redis Function中执行代码是原子操作,执行过程中不会被打断.

注册完毕了,must be implemented,怎么执行呢,就是用FCALL.

FCALL

FCALL myfunc 0 hahahahaha
复制代码

A function name is specified,hahahahaha就是参数1.0我们之后再介绍.

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

image.png

解释FCALL

语法:

FCALL function numkeys [key [key ...]] [arg [arg ...]]
复制代码

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

numkeysRefers to the representatives in the following parametersRedis KeyHow many parameters are there.

It can be followed by a series of parameters,参数有2种:代表Redis key的参数、其它参数.

也就是说,如果你要在lua函数中访问Redis的key,It must be passed in as a parameter,千万不要自己去拼接. 自己拼接keyParameters are in a single machineRedis没问题,但是分布式RedisThere will be big problems.分布式RedisNeed to know you are here「原子操作」may read in/写哪些key,to do some concurrency control,以免读到脏数据.

其它指令

  • FCALL_RO: The function is called in read-only mode(Meaning when the function executes,You cannot writeRedis数据,但可以读取).分布式RedisThere will be optimizations for this mode.
  • FUNCTION DELETE: Remove loadedlua模块(Note that the module dimension is removed).
  • FUNCTION DUMP: Serialize the loaded function,返回byte串.
  • FUNCTION RESTORE: 通过byte串(恢复)加载函数.有3种模式:FLUSH(Empty the loaded and then restore)、APPEND(新增,But the one with the same name is no longer loaded)、REPLACE(新增,and replace the same name).
  • FUNCTION FLUSH: Empty loaded functions.
  • FUNCTION KILL: This command terminates an executing read-only function.
  • FUNCTION LIST: 返回已加载的模块、函数列表.
  • FUNCTION STATS: Get the status of the executing function(函数名、参数信息、How long has it been implemented).Because some functions take too long,会导致RedisThis single thread keeps getting stuck,So by querying the status,The user can decide whether to pass or notFUNCTION KILL终止它.

写在最后

推荐阅读官方文档:redis.io/docs/manual…

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

copyright:author[HullQin],Please bring the original link to reprint, thank you. https://en.javamana.com/2022/266/202209230837006896.html