登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  Redis

Redis Functions 怎样加载可重复调用的服务端函数

来源:17golang原创

时间:2026-10-29 00:21:08 325浏览 收藏

如果一段 Lua 逻辑需要被多个请求反复调用,Redis Functions 的做法是先把“库”加载到 Redis,再用函数名调用,而不是每次把完整脚本重新发过去。最小闭环只有三件事:源码以 #!lua name=库名 开头,库内通过 redis.register_function 注册入口,加载后用 FCALL 函数名 numkeys ... 调用。

官方地址:https://redis.io/docs/latest/develop/programmability/functions-intro/

本文只围绕“怎样加载并重复调用一个服务端函数”展开。下面的命令和输出是用于说明语义的示例,不代表在本文环境中实际运行过。

先判断:应该加载库,还是每次发送脚本

Redis 7 引入的 Functions 把函数作为数据库管理的服务端工件。相比每次用 EVAL 发送脚本,调用方只依赖函数 API;库可以包含多个函数,库名和函数名也比一串 SHA 更容易在排查时识别。

方式代码在哪里适合的调用形态
EVAL客户端请求里临时执行一次脚本
EVALSHARedis 脚本缓存里客户端维护脚本并重复调用
Redis FunctionsRedis 的函数库里先部署库,再由多个调用方按函数名重复使用

选择 Functions 后,第一步不是直接写 FCALL,而是先准备一个可加载的 library。空库会失败,因为 Redis 要求库至少注册一个函数。

一份能加载的最小 Lua 库

下面的库名是 orderlib,函数名是 mark_order。它接收一个订单 key 和一组普通参数,把状态写入 Hash。示例特意把 key 与普通参数分开,后面调用 FCALL 时就能看出 numkeys 的作用。

#!lua name=orderlib

-- 注册一个需要一个 Redis key 的服务端函数。
local function mark_order(keys, args)
  -- keys[1] 必须来自 FCALL 的 key 区域,不能把它当普通参数传入。
  if #keys ~= 1 then
    return redis.error_reply('mark_order requires exactly one key')
  end

  -- 普通参数按顺序放在 args 中:字段名和值各占一个位置。
  if #args ~= 2 then
    return redis.error_reply('mark_order requires field and value')
  end

  return redis.call('HSET', keys[1], args[1], args[2])
end

-- 只有注册后的名字才能通过 FCALL 找到这个函数。
redis.register_function('mark_order', mark_order)

其中 Shebang 的 name=orderlib 是库名,不是函数名;mark_order 才是之后传给 FCALL 的入口名。一个库可以注册多个函数,但它们会随库一起加载和更新。

Redis Functions 库名、Lua 源码、注册函数、key 参数和普通参数之间的静态关系说明图
图1:Redis Functions 库结构说明图,展示库名、注册函数、key 区域和普通参数的静态关系;这是说明图,不是运行截图。

用 FUNCTION LOAD 首次加载,用 REPLACE 整库更新

Redis 的命令语法是 FUNCTION LOAD [REPLACE] function-code。如果源码保存为 orderlib.lua,可以把整个文件通过标准输入交给 redis-cli -x:

# 首次把完整 Lua 库交给 Redis;-x 让 redis-cli 从标准输入读取库源码。
cat orderlib.lua | redis-cli -x FUNCTION LOAD

# 修改库内任意函数后,使用 REPLACE 以整库为单位替换旧定义。
cat orderlib.lua | redis-cli -x FUNCTION LOAD REPLACE

首次加载成功时,返回值是库名 orderlib。如果同名库已经存在而没有写 REPLACE,Redis 会拒绝本次加载;REPLACE 不是只替换一个函数,而是用新的完整库定义覆盖旧库,所以发布时应把库内所有函数一起纳入版本管理。

orderlib
(error) ERR Library 'orderlib' already exists
orderlib

不要把返回的库名误当成函数调用名。加载成功只是说明库被接受,真正调用仍要传入已注册的函数名。

用 FCALL 调用:numkeys 决定参数分区

这个例子里函数只需要一个 key,因此 numkeys 写成 1:

# 1 表示后面的第一个参数是 key;其余两个参数是普通参数。
redis-cli FCALL mark_order 1 order:100 status paid

# 读取刚才由函数写入的字段,用于理解返回值语义。
redis-cli HGET order:100 status
(integer) 1
paid

Redis 会把 order:100 放进 Lua 回调的 keys 表,把 status 和 paid 放进 args 表。如果把 numkeys 写成 0,函数内部的 keys 就为空;如果写成 2,第二个参数也会被当成 key。这个数字不是“参数总数”,而是 key 参数的数量。

在 Redis Cluster 中,函数访问的所有 key 都必须显式出现在 key 区域,并且同一次调用的 key 要满足集群的路由约束。不要把 key 拼在普通参数里来绕过这个边界。

FCALL 的函数名、numkeys、Redis key、普通参数和函数返回值之间的静态边界说明图
图2:FCALL 参数边界说明图,展示 numkeys 如何把输入分成 keys 与 args;这是结构图,不是运行截图。

加载完成后怎样判断没有走错

可以按“库—函数—调用参数”三个层次判断。先用 FUNCTION LIST 查看库名和已注册函数,再用一次最小 FCALL 检查函数名与 key 数量是否一致:

# 列出服务端已加载的库和函数元数据。
redis-cli FUNCTION LIST

# 本例的 mark_order 会写 Hash,所以使用普通 FCALL。
redis-cli FCALL mark_order 1 order:100 status shipped

排查时重点看这几类结果:

  • 返回 ERR No functions registered:库源码只有 Shebang,没有调用 redis.register_function。
  • 返回“库已存在”:首次加载命令重复执行,确认是否应该使用 REPLACE。
  • 函数报 key 数量错误:检查 FCALL 的 numkeys,不要先改 Lua 逻辑。
  • 集群只有部分节点能找到函数:Redis Cluster 需要由管理员把库加载到所有 master 节点;副本传播不等于集群所有 master 自动完成部署。

Redis Functions 的执行仍然是原子的,并会在执行期间阻塞服务器处理其他活动,因此函数应保持短小,不能把长时间计算或等待外部资源的工作塞进一次函数调用。

常见问题

FUNCTION LOAD 返回的是函数名吗?

不是。成功返回加载的库名;函数名来自 redis.register_function,之后由 FCALL 使用。

修改一个函数时能否只上传这个函数?

不能把库当成可选择更新的函数集合。Redis Functions 以库为更新单位,使用 FUNCTION LOAD REPLACE 时应提交包含全部注册函数的完整库源码。

总结一下:先用带 Shebang 的 Lua 源码注册函数,再用 FUNCTION LOAD 首次加载、用 REPLACE 更新整库,最后通过正确的 numkeys 把 key 与普通参数分开传给 FCALL。这样库的部署动作和业务调用动作就能清晰分离。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>