redis 7.0 functions 是将服务端逻辑作为数据库对象管理的新机制,解决 eval/evalsha 在主从切换、重启后因脚本仅存内存而不持久导致的 noscript 错误;function load 落盘同步至 aof/rdb/从节点,支持可观测性、细粒度 acl、硬隔离 lua 环境及强制注册规范。

Redis 7.0 的 Functions 不是“Lua 脚本的增强版”,而是把服务端逻辑当作数据库对象来管理的新机制——它解决的是传统 EVAL/EVALSHA 在生产环境里根本不可靠的问题。
FUNCTION LOAD 会落盘并同步,SCRIPT LOAD 只存内存
旧脚本靠 SCRIPT LOAD 注入,但 Redis 明确不把它写进 AOF/RDB,也不复制到从节点。主节点重启、主从切换、集群分片迁移后,EVALSHA 必报 NOSCRIPT No matching script。这不是配置漏了,是设计如此。
FUNCTION LOAD 则不同:函数库被当成数据写入 AOF、参与 RDB 快照,并通过主从复制自动同步到所有节点。你 reload 一次,整个集群都认得 mylib.myfunc。
- 调用时直接
FCALL mylib.myfunc 1 key1 100,不用管 SHA1、不用预加载、不担心路由错位 -
FUNCTION LIST可查所有已注册函数,FUNCTION STATS能看到错误率和耗时,可观测性拉满 - ACL 权限可精确到函数级别,比如
+function|call ~stats.*,比开放整个+eval安全得多
函数必须显式注册,不能裸写 Lua
Functions 对 Lua 环境做了硬隔离,直接把老 EVAL 脚本塞进去,90% 会失败。典型报错:attempt to call a nil value (global 'redis') 或 Lua redis() command arguments must be strings or integers。
必须满足三条铁律:
- 第一行且仅第一行,必须是
#!lua name=lib:xxx(空行、注释、多空格都不行);version=1可选但建议加上 - 命令名全小写:
redis.call("incr", key)合法,redis.CALL("INCR", key)直接报错 - 禁用全局变量和非安全模块:删掉
os.time()、io.open()、loadstring()—— 这些在 Functions 里根本不存在
合法开头示例:#!lua name=lib:analytics version=1,然后紧跟 redis.register_function("sum_recent", function(keys, args) ... end)。
Redis 8.2.3 是一款安全优先的高性能键值存储系统。该版本紧急修复了可能引发远程代码执行(RCE)的高危漏洞(CVE-2025-62507),并解决了 HyperLogLog 及 Cuckoo Filter 等数据结构在特定场景下的崩溃问题。建议所有用户立即升级,以保障生产环境的系统稳定与数据安全。
函数执行仍阻塞主线程,但结构更可控
和 EVAL 一样,Functions 运行期间独占 Redis 单线程。一个函数里循环十万次、调用 KEYS *、或试图做 I/O,结果就是所有客户端命令排队,延迟飙升。
但 Functions 强制你拆解逻辑:
- 不能把所有计算塞进一个函数里;复杂逻辑要拆成多个小函数,各自职责清晰
- 没有全局状态,每次调用都是干净的沙箱实例;计数器、缓存等必须显式传参或读写 key
- 不支持单个函数热更新;改一个函数就得整库重载(用
REPLACE),避免版本错乱
ACL 权限和可观测性是真实可用的,不是摆设
旧版 Lua 脚本权限只能开 +eval,等于把整个服务端执行能力交出去。Functions 支持细粒度控制:ACL SETUSER alice +function|call ~cart.* -function|call ~admin.* 是可行的。
更重要的是,FUNCTION STATS 返回的是真实指标:执行次数、错误数、平均耗时、最后调用时间戳。这些数据能直接喂给 Prometheus 做告警,而不是靠日志 grep 猜问题。
真正容易被忽略的点是:Functions 的“版本”不是语义化版本号,而是每次 FUNCTION REPLACE 自动生成的递增 ID;回滚靠 FUNCTION FLUSHDB libname version_id,不是 git checkout。这个 ID 不透明,也难追踪,上线前最好自己记日志。










