redis 7.0集群不支持select切库,必须用acl+key pattern+命令白名单组合实现多租户隔离;acl文件需绝对路径且独立配置,禁用requirepass,key pattern如~tenant_a:限定数据可见性,须显式配置-select +select|0,并为pub/sub添加&tenant_a:权限。

Redis 7.0 集群不支持 SELECT 切库,所以「按 database 隔离」这条路根本走不通;必须用 ACL + key pattern + 命令白名单三者组合,才能实现真正可用的多租户权限隔离。
ACL 文件必须独立配置,不能和 requirepass 共存
Redis 启动时会校验配置一致性:如果 redis.conf 里同时存在 requirepass 和 aclfile,进程直接退出并报错 FATAL CONFIG FILE ERROR。
- 删掉所有
requirepass行(包括注释掉的),哪怕你只打算给default用户设密码 -
aclfile路径必须是绝对路径,且 Redis 进程有读取权限(常见坑:/etc/redis/users.acl权限为600,属主是root,但redis用户无法读) - 集群每个节点的
redis.conf都要配相同的aclfile路径,否则节点间 ACL 状态不一致,ACL LIST结果可能不同步
key pattern 是租户隔离的物理基础
集群模式下所有命令都基于 slot 计算,~tenant_a:* 这类 pattern 才能真正限制数据可见性;光靠命令权限(如 +@read)无法阻止用户读别人前缀的 key。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- pattern 中不能用
~*—— 这等于开放全量 key,租户可互相扫描 - 多个 pattern 用空格分隔,例如
~order:* ~user:* ~cache:*,但注意这会扩大攻击面 - pattern 不支持正则,只认
*和?;~tenant_a:**无效,得写成~tenant_a:* ~tenant_a:*:* ~tenant_a:*:*:*(实际中建议扁平化 key 设计) - 如果业务需要通配二级结构(如
tenant_a:session:*和tenant_a:profile:*),直接写~tenant_a:session:* ~tenant_a:profile:*
集群场景下 SELECT 命令必须显式禁用再放行
虽然集群只用 db0,但客户端仍可能发 SELECT 0。如果不处理,ACL 会默认允许——而一旦允许,某些 SDK(如旧版 Jedis)会自动在连接后执行 SELECT 0,导致认证失败。
- 正确写法是:
-SELECT +SELECT|0,先全局禁止,再特许SELECT 0 - 别漏掉
+SELECT|0,否则 Java 客户端调jedis.select(0)会抛NOPERM - 集群节点之间通信也走 client 协议,所以 ACL 规则对内部命令同样生效;禁止
SELECT不影响集群心跳
Java 客户端连接必须传 username,不能只传 password
Jedis/Lettuce 如果只调 auth("pwd"),实际发的是老式 AUTH 命令,Redis 会尝试用 default 用户匹配,但该用户若被 ACL 显式禁用(如 user default off),连接直接断开。
- Jedis 写法:
jedis.auth("tenant_a", "pwd_a"),两个参数缺一不可 - Lettuce 推荐用 URI:
redis://tenant_a:pwd_a@127.0.0.1:7001/0,注意末尾/0是 db index,集群下固定为 0 - Spring Data Redis 3.2+ 支持
RedisStandaloneConfiguration.setClientName(),但 username 需通过RedisClientConfiguration的clientOptions注入,不是 setUserName
最容易被忽略的一点:ACL 规则里写的 ~tenant_a:* 只控制 key 访问,不控制 Pub/Sub 频道;如果租户要用 PUBLISH/PSUBSCRIBE,还得加 &tenant_a:*,否则订阅失败静默无提示。










