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

Redis Functions 怎样在集群中预加载函数

来源:17golang原创

时间:2026-11-03 04:52:40 440浏览 收藏

Redis Functions 预加载到集群时,关键不是在一个入口节点执行一次 FUNCTION LOAD,而是把同一份函数库加载到每个主节点。Redis Cluster 的数据按槽分布,函数库的可用性也不会由 Cluster 自动替你完成;官方文档建议使用 redis-cli --cluster-only-masters --cluster call 批量发送加载命令。

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

要点速览
  • FUNCTION LOAD 只影响当前节点,集群部署要面向所有主节点加载。
  • 库的 shebang、库名、注册函数和 FCALL 的键参数必须保持一致。
  • 更新库用 REPLACE,它替换的是整个库;跨槽多键访问仍受 Cluster 路由约束。

为什么单节点 FUNCTION LOAD 在集群里不够

Redis Functions 是 Redis 7 引入的服务端函数能力。函数属于库,加载后可以被客户端用 FCALL 调用,并且库会随数据持久化和主从复制保存。这里容易混淆的一点是:副本复制不等于集群主节点之间的同步。Cluster 不会因为你连上一个主节点,就把函数库自动复制到其他主节点。

因此,单节点执行下面的命令只能说明“当前节点认识 cartlib”,不能说明其他分片也认识它:

# 单节点示例:只把库发送给当前连接的 Redis 节点
cat cart_functions.lua | redis-cli -h 127.0.0.1 -p 6379 -x FUNCTION LOAD REPLACE

先把函数库做成可重复加载的 payload

函数库必须以 shebang 声明执行引擎和库名,并至少注册一个入口函数。下面的库只操作一个库存键,函数名和库名都保持稳定,方便发布脚本和检查脚本复用。

#!lua name=cartlib

-- 只接收一个库存键,避免把未声明的键藏在普通参数里
local function reserve(keys, args)
  local stock_key = keys[1]
  local amount = tonumber(args[1])
  if not amount or amount 

调用时,FCALL reserve_stock 1 stock:{sku-42} 2 中的 1 表示后面第一个参数是键名,只有它会进入 keys 表;2 是普通参数。函数访问的每个键都应显式列在键参数中,这样 Cluster 才能根据哈希槽做路由。若一个函数必须同时访问多个键,调用方应让它们使用相同的 hash tag,例如 order:{42} 与 stock:{42}。

用 cluster call 把同一库加载到所有主节点

准备好库文件后,将加载动作交给 Cluster 管理命令。命令中的入口地址只是集群命令端口,不是 cluster bus 端口;生产环境还要按自己的认证和 TLS 参数补充连接选项。

Redis Functions 的 Lua payload、FUNCTION LOAD、cartlib 与 Redis Cluster 主节点和副本传播的静态关系说明图
图1:Redis Functions 集群预加载的结构说明图,展示库 payload、主节点和副本之间的静态关系,不是截图或运行证据。
# 从一个集群入口向所有主节点发送同一份库定义
redis-cli --cluster-only-masters --cluster call redis-cluster.example.com:6379 \
  FUNCTION LOAD REPLACE "$(cat cart_functions.lua)"

# 业务调用时显式声明 1 个键,键名使用 hash tag 保证路由稳定
redis-cli -c -h redis-cluster.example.com -p 6379 \
  FCALL reserve_stock 1 stock:{sku-42} 2

首次加载时可以省略 REPLACE;发布新版本时保留它更容易实现幂等重试,但要记住它替换的是整个库,不是只替换其中一个函数。库中其他函数如果漏写,也会随这次替换一起消失,所以发布前应把完整 payload 当作一个版本管理。

检查库名、入口和键路由是否一致

检查不需要执行复杂业务。先按库名查看每个主节点的函数清单,再用一条使用固定 hash tag 的调用确认客户端路由和入口名称匹配:

Redis FCALL 的 reserve_stock、KEYS[1]、stock hash tag、普通参数与 hash slot 路由关系说明图
图2:FCALL 键参数与集群路由的关系说明图,展示显式键、函数入口和 hash tag 边界,不是截图或运行证据。
# 查看目标库及其注册函数,结果应在各主节点保持一致
redis-cli --cluster-only-masters --cluster call redis-cluster.example.com:6379 \
  FUNCTION LIST LIBRARYNAME cartlib

# 这里的 1 与函数代码中的 keys[1] 对应;不要把库存键放进普通参数
redis-cli -c -h redis-cluster.example.com -p 6379 \
  FCALL reserve_stock 1 stock:{sku-42} 1

如果某个节点报库不存在,优先检查加载命令是否只连到了单节点、目标节点是否刚扩容加入、以及发布时使用的库名是否一致。若出现跨槽错误,不要通过改变函数内部访问方式掩盖问题,应重新设计键名的 hash tag 或把跨槽聚合移到客户端。

副本、扩容和回滚时要留意什么

场景处理方式边界
主节点有副本函数会随主从复制传播不能据此替代主节点之间的批量加载
新增节点用官方 Cluster 加节点流程仍要确认新拓扑中的库清单
更新库完整 payload + REPLACE整库替换,不是函数级补丁
删除库FUNCTION DELETE cartlib删除前先停止依赖该库的调用方

另外,Functions 的执行具有原子性并会阻塞 Redis 的其他活动,函数应保持短小;预加载解决的是“函数是否存在”,并不会让长时间运行的函数变成异步任务。只读函数若要在只读副本上用 FCALL_RO,还需要在注册时声明合适的 no-writes 标志。

常见问题

只对一个主节点执行 FUNCTION LOAD,其他主节点能调用吗?

不能把它当作可靠行为。调用被路由到没有该库的节点时会失败,应使用 Cluster 批量命令覆盖所有主节点。

为什么更新时推荐 REPLACE?

它允许同名库用完整新定义覆盖,适合发布脚本重试;代价是必须提交完整库内容,遗漏函数会随整库替换消失。

FCALL 的键数量写错会怎样?

函数收到的 keys 与 args 会错位,轻则业务参数解析失败,重则键路由和跨槽判断不符合预期。调用契约应把键数量、键名格式和普通参数一起固定下来。

把“加载一次”改成“对所有主节点发布同一版本、按库名检查、按键槽调用”,Redis Functions 在集群中的预加载就有了可重复执行的边界。

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