24. 函数 FUNCTION 与 ACL
本教程共 40 篇 · 第 24 篇 · 更新于 2026-08-02
24. 函数 FUNCTION 与 ACL
第 23 章讲了用 EVAL 运行 Lua 脚本。它足够好,但有个治理痛点:脚本源码散落在各个应用实例里,每个实例都得自己持有脚本、自己处理缓存与降级,难以统一管理和版本化。从 Redis 7.0 起,Redis 给出了更好的方案——函数(Function):把脚本变成数据库的“一等公民”,先加载进库、再被所有客户端调用。
另一方面,Redis 暴露在公网或多人共用时,不能让任何人执行任何命令。Redis 6 引入、并在 8.x 持续完善的 ACL(Access Control List,访问控制列表),让你可以创建多个带精细权限的用户。本章把这两项“服务端治理 + 安全防护”的能力一并讲清。
本节目标
- 理解函数(FUNCTION)相比 EVAL 脚本的优势:成为数据库一等公民、集中管理。
- 掌握
FUNCTION LOAD加载、FCALL调用、FUNCTION LIST/FUNCTION DELETE管理。 - 理解 ACL 的由来:取代单一的
requirepass,支持多用户与细粒度授权。 - 用
ACL SETUSER创建用户,配置命令权限(+@cat)、键范围(~pattern)、频道(&pattern)与密码。 - 知道生产环境 ACL 的基本安全建议。
函数 FUNCTION
函数的本质是“加载进 Redis 的命名脚本”。它一经 FUNCTION LOAD 加载,就常驻数据库,所有连接的客户端都能用 FCALL 按名字调用,应用层不再需要持有源码、也不再依赖 EVALSHA 的缓存降级逻辑。
加载一个函数(用 FUNCTION LOAD,Lua 函数需声明 redis.register_function):
127.0.0.1:6379> FUNCTION LOAD "#!lua name=mylib\nredis.register_function('incrby', function(keys, args) return redis.call('INCRBY', keys[1], args[1]) end)"
"mylib"
上面把名为 mylib 的库加载进来,其中注册了一个函数 incrby。随后用 FCALL 调用,参数同样是 函数名 numkeys KEYS... ARGV...:
127.0.0.1:6379> FCALL incrby 1 mycounter 5
(integer) 5
127.0.0.1:6379> FCALL incrby 1 mycounter 5
(integer) 10
常用管理命令:
FUNCTION LIST:列出已加载的函数库。FUNCTION INFO libname:查看某个库的详情。FUNCTION DELETE libname:删除函数库(注意会移除其中所有函数)。FUNCTION FLUSH:清空全部函数(支持ASYNC/SYNC)。FUNCTION KILL:终止正在运行的只读函数(类比SCRIPT KILL)。
函数与脚本一样是原子执行、阻塞全服的,第 23 章关于“不要写慢脚本、留意 busy-reply-threshold”的全部建议,对函数同样适用。只读函数也可用 FCALL_RO 调用,获得在从节点运行、可随时 FUNCTION KILL 等好处。
提示:FUNCTION 是 Redis 7.0 引入的能力,在 Redis 8.x 中已是推荐的服务端编程方式。当你需要在多个应用、多语言客户端间共享同一段服务端逻辑时,优先用 FUNCTION 而非各自
EVAL,可避免“脚本散落、版本不一致”的运维灾难。需要向下兼容老版本集群时,才退回 EVAL。
ACL:多用户与精细授权
在 Redis 6 之前,访问控制只有一个 requirepass——所有连上的人用同一个密码、拥有全部权限。这显然不适合多团队共用或对外暴露的实例。ACL 让 Redis 支持多个用户,每个用户可以被精确限制“能执行哪些命令、能碰哪些 key、能访问哪些频道”。
Redis 默认存在一个 default 用户。新连接若以 default 且 nopass 登录,就拥有全部权限(这也是很多开发环境“裸奔”的原因)。用 AUTH 以特定用户登录:
127.0.0.1:6379> ACL WHOAMI
"default"
创建受限用户
用 ACL SETUSER 创建用户。规则语法(与 redis.conf 中 user 指令一致):
on/off:启用 / 禁用该用户;>password:设置密码(<password删除,nopass表示免密);+<cmd>/-<cmd>:允许 / 禁止某命令,+@<category>允许某类命令;~<pattern>:允许访问的 key 模式(~*表示所有);&<pattern>:允许访问的 Pub/Sub 频道模式。
下面创建一个只能操作 list 类命令、且只能碰 jobs:* 这个 key 前缀、免密的用户 worker:
127.0.0.1:6379> ACL SETUSER worker on nopass +@list +@connection ~jobs:* &
OK
用该用户登录后,只能对 jobs: 开头的 key 用 list 命令:
127.0.0.1:6379> AUTH worker ""
OK
127.0.0.1:6379> RPUSH jobs:queue task1
(integer) 1
127.0.0.1:6379> GET jobs:queue
(error) NOSCRIPT ... WRONGTYPE ... (error) ACL denied ...
(最后一行被拒绝,因为 worker 没有 +@string 的 GET 权限,且 ~jobs:* 之外的 key 也被禁止。)
命令类别与最小权限
@list、@string、@set、@sortedset 等是命令类别,可用 +@类别 批量授权。特殊类别有:
@all:所有命令(allcommands是其别名)。@admin:管理类高危命令(如FLUSHALL、CONFIG、SHUTDOWN、ACL)。@dangerous:危险命令集合。
生产上遵循最小权限原则:给应用账号只开它真正需要的类别,并尽量用 ~appname:* 限制 key 前缀,避免它误删别人的数据。
其他 ACL 命令:
ACL LIST:列出所有用户及其规则。ACL GETUSER name:查看某用户详情。ACL WHOAMI:当前连接所用用户。ACL DELUSER name:删除用户。ACL LOG:查看因 ACL 被拒绝的命令记录,便于排查。
提示:用
aclfile配置项可把 ACL 规则写到独立文件,由ACL LOAD加载;这与requirepass互斥。生产环境推荐用外部 ACL 文件管理用户,而不是把规则写死在redis.conf里,便于集中运维与版本控制。注意default用户若设了密码,新连接就必须AUTH,这正是“关掉裸奔”的关键一步。
安全小建议
- 永远给
default用户设密码,或干脆禁用它(ACL SETUSER default off)。 - 应用使用专用低权限用户,按业务划分 key 前缀与命令类别。
- 配合
protected-mode yes与绑定内网地址,不要把 Redis 裸暴露到公网。 - 高危命令可用 ACL 重命名或禁用(如把
FLUSHALL仅对管理员开放)。
小结
- 函数 FUNCTION 是 Redis 7+ 推荐的服务端编程方式:用
FUNCTION LOAD加载、FCALL调用,逻辑常驻数据库、集中管理,优于散落的 EVAL。 - 函数同样原子、阻塞全服,请遵循“短脚本”原则;只读函数用
FCALL_RO。 - ACL 取代了单一
requirepass,支持多用户与最小权限:命令(+@cat)、key(~pattern)、频道(&pattern)、密码(>pw)四个维度。 - 用
ACL SETUSER建用户、ACL LIST/ACL LOG排查;生产用外部 aclfile 管理。 - 安全底线:关掉 default 裸奔、应用用低权限专用账号、不裸暴露公网。
常见误区
- 误区一:把 FUNCTION 当成“更好的 EVAL”就随便用。 函数的优势是“常驻数据库、集中管理”,但它和脚本一样原子且阻塞全服。如果函数逻辑写得很长、遍历超大集合,危害与慢脚本完全相同——会卡住整个实例。务必保持函数短小。
- 误区二:以为 ACL 只是“多设几个密码”。 ACL 的精髓是最小权限:用
+@类别限定命令、~pattern限定 key 前缀、&pattern限定频道。给应用开一个“只能碰自己业务 key、只有需要的命令类别”的专用账号,远比共享一个全权限账号安全。 - 误区三:忘了关掉
default用户的“裸奔”。 默认default用户常是nopass且拥有全部权限,任何人连上就能为所欲为。生产环境应给default设密码或干脆ACL SETUSER default off,再为应用创建受限用户。 - 误区四:把
requirepass和aclfile混用。 二者互斥:一旦用外部 ACL 文件(aclfile),就不能再用单密码模式。迁移到 ACL 体系时,记得把旧requirepass逻辑迁进用户规则里,否则启动会报错。
提示:本教程统一基于 Redis 8.x(最新稳定版)行文。补充说明:官方 redis.io 下载页另标 8.8 为 “Latest stable”,而 GitHub 上的最新发布 tag 为 8.10.0,二者同属 8.x 大版本,对 FUNCTION 与 ACL 命令及语义的讲述没有影响。