Redis多租户隔离不能仅依赖db参数,因db=0~15仅为逻辑隔离、共享内存与连接资源;必须结合独立连接池、租户前缀空值缓存、按租户布隆过滤器及超时监控等多重手段实现安全与性能保障。

用不同 db 参数分租户,但别只靠它
Redis 原生支持 16 个数据库(db 0 到 db 15),最直接的隔离方式是给每个租户分配独立 db。比如租户 A 用 db=0,租户 B 用 db=1,连接池初始化时就指定好:ConnectionPool(host='localhost', port=6379, db=0)。
但这只是逻辑隔离,不是安全边界:Redis 的 SELECT 命令可随意切换 db,且所有 db 共享同一内存、同一连接数、同一慢日志和同一监控指标。一旦某个租户缓存穿透打爆 db=0,整个实例响应变慢,db=1 也会卡顿。
所以 db 隔离仅适合低风险、低流量租户,或作为辅助手段;高敏感/高并发租户必须叠加其他措施。
缓存空值 + 租户前缀双保险,防穿透不防错
穿透本质是“查一堆根本不存在的 key”,而多租户场景下,key 本身可能带租户上下文(如 user:tenant_a:123)。如果攻击者构造 user:tenant_a:-1、user:tenant_a:9999999 这类非法 ID,空值缓存必须带上租户标识,否则会污染其他租户:
- ✅ 正确做法:缓存空值时严格使用带租户前缀的 key,例如
cache.set("user:tenant_a:-1", "", 60) - ❌ 错误做法:统一缓存
"user:-1",所有租户共享这个空值,导致租户 B 查询user:-1也被拦住 - ⚠️ 注意:空值过期时间要短(30–60 秒),避免长期占用内存;同时需配合接口层参数校验(如 ID 格式、范围),不能全押在缓存上
布隆过滤器按租户加载,别共用一个全局 filter
布隆过滤器(Bloom Filter)能高效判断 key 是否可能存在,但它的误判率和重建成本决定了它不能“一滤通用”。若所有租户共用同一个 filter,当租户 A 的合法 key 集合变化时,filter 重建会影响租户 B 的判断准确率,甚至把 B 的有效 key 判为“不存在”。
实际部署建议:
- 每个租户维护自己的布隆过滤器实例,key 命名带上租户标识,如
bloom:tenant_a:user_id - 用 Redis 的
BF.RESERVE+BF.ADD初始化,配合定时任务或事件驱动更新(如用户批量导入后触发 rebuild) - 首次查询先查 filter,命中才查缓存/DB;未命中则直接返回空,不穿透——但必须容忍约 1%~3% 的误判,因此关键业务仍需 fallback 到空值缓存兜底
连接池 + 超时 + 监控三件套,守住资源底线
穿透请求一旦发起,哪怕最终返回空,也会消耗连接、CPU 和网络。没有资源节流,1000 QPS 的穿透足以拖垮 Redis 实例。
必须为每个租户配置独立连接池,并设硬性约束:
-
max_connections:按租户等级分配,核心租户给 50,试用租户给 10,防止一个租户占满全部连接 -
socket_timeout和connect_timeout:统一设为 ≤ 1s,避免慢查询堆积阻塞线程 - 启用
health_check_interval(如 30 秒),自动剔除异常连接 - 接入监控时,按租户维度采集指标:比如
redis_pool_tenant_a_active_connections,而不是只看全局connected_clients
最关键的细节常被忽略:连接池隔离必须和业务线程模型对齐。如果你用的是 Spring Boot WebMvc(非响应式),每个租户的请求必须路由到对应连接池的 RedisTemplate 实例,不能靠运行时动态切换 setConnectionFactory——那会破坏连接复用,反而加剧资源争抢。











