基于NestJS/PostgreSQL的Redis嵌套层级数据缓存最优方案问询
PostgreSQL层级数据的Redis缓存最优方案
核心思路:拆分缓存粒度+关联索引
不再直接缓存全量接口响应,而是拆分基础实体缓存、权限关联索引、层级关联索引三层,按需聚合数据,既减少重复缓存,又缩小更新影响范围。
1. 基础实体缓存(单条数据存储)
用Redis哈希(Hash)存储单个space、folder、file的完整数据,键命名规则统一为:
- Space:
space:[SPACE_ID],字段包含name、another_attribute、user_ids(逗号分隔的有权限用户ID列表) - Folder:
folder:[FOLDER_ID],字段包含space_id、name、user_ids - File:
file:[FILE_ID],字段包含folder_id、space_id、name、user_ids
2. 权限与层级关联索引
用Redis集合(Set)存储用户权限范围和实体层级关系:
- 用户可访问的实体ID列表:
user:[USER_ID]:spaces:存储该用户有权限的Space ID集合user:[USER_ID]:folders:存储该用户有权限的Folder ID集合user:[USER_ID]:files:存储该用户有权限的File ID集合
- 实体层级关系:
space:[SPACE_ID]:folders:存储对应Space下的Folder ID集合folder:[FOLDER_ID]:files:存储对应Folder下的File ID集合
3. 接口聚合缓存(按需索引)
对于/my-files这类聚合查询接口,仅缓存查询对应的实体ID索引,而非完整响应:
- 键规则:
user:[USER_ID]:files:index:[QUERY_HASH],值为符合查询条件的File ID列表(JSON格式存储) - 接口响应流程:先读取该ID列表,再通过Redis的
HMGET或批量哈希查询获取所有File的详细数据,最后组装成接口响应返回。
缓存更新与失效策略
单个File更新时
- 更新
file:[FILE_ID]哈希中的对应字段; - 从
file:[FILE_ID]的user_ids字段取出所有关联用户,批量删除这些用户下匹配user:[USER_ID]:files:index:*的聚合缓存键; - 若File所属Folder或Space存在层级聚合缓存,按需失效对应索引(如
folder:[FOLDER_ID]:files若有排序需求需同步更新)。
单个Folder更新时
- 更新
folder:[FOLDER_ID]哈希中的对应字段; - 若权限用户变更,同步新增/移除对应
user:[USER_ID]:folders集合中的ID; - 失效该Folder下所有File关联的用户聚合缓存,以及
space:[SPACE_ID]:folders的层级索引(若需更新)。
单个Space更新时
- 更新
space:[SPACE_ID]哈希中的对应字段; - 若权限用户变更,同步新增/移除对应
user:[USER_ID]:spaces集合中的ID; - 失效该Space下所有Folder、File关联的用户聚合缓存。
方案优势
- 缓解缓存体积过大:基础实体仅存储一份,用户缓存仅存ID索引,避免重复存储全量响应数据;
- 缩小更新影响范围:仅失效关联用户的相关聚合缓存,无需全局清理所有用户的缓存,更新效率大幅提升。
内容的提问来源于stack exchange,提问作者Mansouri Rayen
相关产品推荐
相关产品推荐

