5分钟缓存策略具体是如何分层设计缓存结构的?+

Not Quite RARBG(NQRBG)5 分钟缓存策略优化方案:提速 API 响应

一、先搞懂场景现状

Not Quite RARBG 是 RARBG 闭站后的镜像 / 聚合 API 服务,核心业务:

  1. 对外接口:影视资源列表、检索搜索、剧集详情、种子信息、分类榜单、筛选过滤
  2. 原始数据源:爬取源站数据、第三方种子索引、解析页面 HTML、请求外部 Torrent 接口
  3. 原生痛点:
    • 实时爬取 / 实时转发第三方接口:网络 IO 耗时高、外部接口限流、超时、高并发下接口排队阻塞
    • 高频重复请求:大量用户搜热门影视、访问首页榜单、热门分类,相同入参反复拉取远端数据
    • 不加缓存:每次请求都走远端 → P95 响应慢、服务器带宽压力大、极易被源站封禁 IP

核心方案:全局默认 5 分钟(300s)TTL 缓存,分层设计缓存结构,针对性优化 API 响应耗时

二、5 分钟缓存为什么适配 NQRBG 业务

1)业务数据更新频率匹配

RARBG 类种子资源特性:

  • 热门榜单、首页推荐、影视分类列表:5 分钟内数据几乎无变动,新种子不会毫秒级刷屏更新
  • 影视详情页:影片基础信息不变,新增种子是缓慢增量更新,5 分钟延迟用户无感知
  • 搜索结果:短时间内同一关键词返回列表高度重合
  • 缺点容忍度:5 分钟数据延迟对于下载种子场景完全可接受,不会影响正常使用

2)5 分钟 TTL 的取舍优势

表格

维度太短(30s/60s)5 分钟 (300s)过长(30min+)
接口响应缓存命中率低,大量击穿回源命中率高,回源请求大幅削减数据陈旧,用户看到失效种子
源站压力频繁爬取,极易风控拉黑回源频次可控,IP 安全脏数据堆积,需主动清理
内存占用缓存条目刷新快,GC 频繁缓存条目数量平稳,内存可控缓存键暴增,内存溢出风险
并发抗压提升有限并发暴涨时挡住绝大部分回源请求雪崩风险(批量过期瞬间击穿)

3)性能收益理论值

假设原始远端请求平均耗时:800ms ~ 2s(外网爬取 + 解析耗时) 命中 5 分钟缓存后:本地内存 / Redis 读取耗时< 5ms单次请求响应速度提升:160 倍~400 倍;叠加高并发,排队、TCP 握手、远端超时问题全部被隔离。

三、分层缓存架构(5 分钟为基础 TTL,差异化微调)

层级 1:本地内存缓存(进程级 LRU Cache,TTL=300s)

适用:高频热点接口(首页榜单、热门排行、固定分类)

  • 技术选型:Python (functools.lru_cache、cachetools) / Node (lru-cache)
  • 优势:无网络开销,读取纳秒级,极致提速
  • 短板:多实例部署时缓存不共享、进程重启缓存清空
  • 配置规则:

    plaintext

    max_size:依据服务器内存设置上限,防止内存泄漏 default_ttl = 300s 超大搜索结果(分页100+条)降低缓存最大存储数量

层级 2:分布式 Redis 缓存(全局统一 5min 基准 TTL)

整个 NQRBG 集群共用,核心缓存层

  1. 普通只读接口:KEY TTL = 300s(标准 5 分钟) 接口:/list、/category、/search、/details
  2. 差异化微调(基于 5 分钟浮动,不推翻基准)
    • 实时种子活跃度 / 在线人数:TTL=60s(数据变动快)
    • 冷门影视检索、无人访问资源:TTL 延长至 10min,减少无效回源
    • 首页 TOP 榜单:固定 5min 不变
Redis Key 规范(避免缓存错乱)

plaintext

# 格式:nqrbg:{接口名}:{序列化请求参数哈希} 例: nqrbg:search:md5(关键词+页码+排序方式+筛选条件) nqrbg:category:md5(分类id+页数)

参数做哈希序列化,不同分页、不同筛选条件生成独立缓存键,不会出现数据错乱。

层级 3:磁盘持久缓存(兜底冷数据,5min 内存缓存失效后兜底)

将爬取的原始 HTML、原始种子元数据落地本地文件 / 对象存储,Redis 回源失败时直接读取磁盘缓存,防止接口雪崩。

四、5 分钟缓存配套优化策略(只开 TTL 没用,必须搭配)

1. 缓存击穿、雪崩、穿透防护(5min 固定 TTL 必做)

1)缓存雪崩:统一 5min 过期,大量 key 同一时间回源解决:给 TTL 增加随机抖动300 ± 30s,真实过期时间:270s ~ 330s,打散批量过期时刻

plaintext

final_ttl = 300 + random.randint(-30, 30)

2)缓存击穿:某个热门资源缓存到期瞬间大量请求打向源站方案:互斥锁(Redis Redlock)+ 热点 key 永不过期 + 后台异步 5 分钟主动刷新(主动预热) 3)缓存穿透:非法参数、不存在的影视 ID 大量查询,缓存永远为空一直回源方案:空结果也写入缓存,空数据 TTL 依旧 5min,避免无效回源轰炸源站

2. 接口粒度划分 + 缓存开关

  • GET 查询接口:全部开启 5 分钟缓存(99% 流量接口)
  • POST 提交、资源上报、种子校验接口:关闭缓存(动态写入操作)
  • 管理员后台接口:强制绕过缓存,实时拉取最新数据

3. 异步预刷新(主动缓存,进一步抹平响应延迟)

单纯被动缓存:用户第一次访问等待远端请求(慢),后续 5 分钟才快 优化方案: 热门榜单、首页数据 → 后台定时任务每 4.5 分钟主动请求一次源站刷新缓存用户永远命中现成缓存,首次访问也无等待耗时,5min 过期前提前更新。

4. 响应数据压缩 + 缓存 value 精简

存入 Redis 的缓存数据:

  1. 剔除页面无用 HTML 标签、冗余字段、无用注释
  2. JSON 开启 gzip 压缩存入 Redis,减少 Redis 内存占用、网络传输耗时
  3. 分页数据单独缓存,不要一次性缓存全量数据集

五、5 分钟缓存落地实施步骤

  1. 灰度上线先对首页、榜单接口开启 300s 缓存,观测:缓存命中率、API 平均 RT、源站请求量 指标目标:源站回源请求量下降 70% 以上,接口平均 RT 下降 80%+
  2. 全量铺开检索、详情接口 5min 缓存增加空值缓存、TTL 随机抖动、热点预热任务
  3. 监控看板搭建监控指标:缓存命中率、缓存平均读取耗时、回源失败率、接口 P95/P99 响应时间
  4. 异常兜底:远端源站不可用时,无限复用现有 5 分钟缓存数据,接口不报错降级返回旧数据

六、可落地代码示例(Node.js + Redis 标准 5 分钟缓存封装)

javascript

运行

const Redis = require('ioredis'); const redis = new Redis({ host: '127.0.0.1', port: 6379 }); const BASE_TTL = 300; const TTL_JITTER = 30; // 缓存包装高阶函数 function withNQRBGCache(fn) { return async (...args) => { const cacheKey = `nqrbg:${fn.name}:${JSON.stringify(args)}`; // 读取缓存 const cacheData = await redis.get(cacheKey); if (cacheData) return JSON.parse(cacheData); // 回源请求真实API/爬虫 const resData = await fn(...args); // 空数据也缓存 const realTTL = BASE_TTL + Math.floor(Math.random() * TTL_JITTER * 2 - TTL_JITTER); await redis.set(cacheKey, JSON.stringify(resData), 'EX', realTTL); return resData; }; } // 原始爬取函数 const fetchRarbgSearch = async (keyword, page) => { // 远端请求、页面解析、种子整理逻辑 }; // 包装5分钟缓存 const cachedSearch = withNQRBGCache(fetchRarbgSearch);

七、优化前后指标对比参考

表格

指标无缓存单纯 5min 缓存5min 缓存 + 抖动 + 主动预热
平均响应耗时1100ms6ms3ms
P99 响应耗时2300ms12ms7ms
源站请求 QPS100%25% 左右10% 以内
IP 封禁风险极低
服务器带宽消耗大幅降低最优

八、补充运维注意点

  1. 不要设置永久缓存,5 分钟 TTL 自带过期清理,无需手动大批量删除 key
  2. 若推送官方种子更新通知,提供手动清除指定 key 的接口,强制刷新缓存
  3. 容器多实例部署时统一使用 Redis 分布式缓存,不要只依赖本地内存缓存

如果你需要,我可以根据你的开发栈(Python/Node)、当前 NQRBG 的接口结构,给你一份完整可直接部署的缓存中间件完整代码 + 缓存监控埋点写法

5分钟缓存策略具体是如何分层设计缓存结构的?

Not Quite RARBG 五层分层缓存架构(基准 TTL 固定 5 分钟,逐层降级、逐级加速)

整体链路:客户端内存缓存 → 服务端本地内存 L1 缓存 → Redis 分布式 L2 主缓存 → 磁盘持久化 L3 冷备份缓存 → 上游源站回源基准过期时间统一锚定300s(5 分钟),每层基于 5min 做微调适配,各司其职,不会出现多层 TTL 混乱。 整体请求流程:客户端请求 → L1 命中直接返回 → 未命中查 L2 → L2 命中返回 → L2 失效读取 L3 磁盘兜底 → L3 无数据才发起爬虫 / 上游 API 回源,回源数据逐级回填所有上层缓存。

前置统一规则

  1. 基础 TTL 基准值:固定 = 300s
  2. 所有定时过期时间附加 ±20~30s 随机抖动,规避批量 key 同一时刻过期引发缓存雪崩
  3. 只读查询接口全部启用分层缓存;写入、管理接口直连源站、跳过全部缓存

第一层:客户端浏览器缓存(浏览器 Http Cache,5min 基准)

作用

把静态接口响应缓存在用户浏览器,相同用户短时间重复刷新、重复搜索不再向服务端发请求,最前置的流量拦截层。

配置方式(HTTP 响应头)

http

Cache-Control: public, max-age=300 ETag: 数据哈希值
  • TTL:严格 5 分钟
  • 适用接口:榜单、分类列表、搜索结果、影视详情这类静态查询接口
  • 短板:单用户隔离,多用户无法共享缓存;清除依靠浏览器自动过期

第二层:服务端本地内存缓存 L1(进程级 LRU 缓存,核心热点高速层|TTL=300s)

技术选型

Node:lru-cache;Python:cachetools.TTLCache

定位:极致低延迟第一层服务端缓存

Redis 存在内网 TCP 网络开销(0.1~1ms),本地内存读取耗时微秒级,专门承接全站TOP 热点接口:首页榜单、排行榜、热门分类。

配置参数

  1. 默认 TTL:300s(附带随机抖动)
  2. 淘汰策略:LRU,设置最大容量,防止内存溢出
  3. 数据范围:只缓存高频热数据,大体积分页结果不存入本地内存
  4. 数据同步规则:L1 缓存失效后,自动从下层 Redis 拉取数据回填本地内存

优缺点

✅ 读取速度最快,无网络消耗,扛住瞬时高并发流量洪峰 ❌ 多实例部署时缓存不互通、容器重启数据清空,只做加速,不作为可靠存储

第三层:Redis 分布式缓存 L2(全局核心主缓存|基准 TTL=300s)

整个集群所有实例共享的标准缓存层,整套 5 分钟缓存策略的核心载体,所有接口标准数据都存在这里。

1)统一 Key 设计范式

plaintext

nqrbg:[接口标识]:[参数哈希串] 示例: nqrbg:search:md5(关键词+页码+排序+筛选条件) nqrbg:category:md5(分类ID+分页) nqrbg:detail:md5(影片id)

不同请求参数生成唯一 Key,避免不同搜索条件互相串数据。

2)基于 5 分钟基准的差异化 TTL 微调(不脱离 5min 主体)

表格

接口类型基础 TTL实际过期时间(带抖动)说明
首页榜单、热门排行300s270~330s标准 5 分钟,数据变化平缓
普通搜索、影片详情300s270~330s用户对 5 分钟延迟无感知
种子实时健康度 / 连接数60s(短 TTL)50~70s动态数据,缩短缓存
冷门资源、低访问量数据600s(10min)540~660s减少无效回源请求
查询为空的结果(无资源)300s270~330s空值缓存,拦截缓存穿透

3)配套加固策略(搭配 5min 必加)

  1. TTL 随机抖动:解决大批量 Key 同时过期、瞬间击穿源站
  2. 热点 Key 主动刷新:热门榜单用定时任务4 分 30 秒主动更新缓存,用户永久命中热缓存,不会遇到第一次访问等待回源的卡顿
  3. 缓存击穿防护:热门资源缓存过期时增加分布式互斥锁,同一时间只放行一个请求回源

4)存储优化

JSON 数据经过 gzip 压缩后存入 Redis,降低内存占用与内网传输耗时。

第四层:磁盘文件缓存 L3(持久化兜底缓存|文件数据有效期 5min + 兜底复用)

定位

Redis 服务宕机、Redis 缓存全部失效时的保底层;同时存放爬虫原始 HTML 源码、原始种子元文件。

设计规则

  1. 回源拿到源站原始数据后,一份存入 Redis,另一份落地磁盘(按接口、参数哈希命名文件)
  2. 磁盘文件本身物理留存时间更长(例如保留 2 小时),但业务层面只认可 5 分钟内的文件为有效数据
  3. 当 Redis 完全不可用,服务自动降级读取磁盘 5 分钟内的旧数据对外返回,保证 API 不会大面积报错、502 雪崩

目录分层存储示例

plaintext

./disk_cache/ ├─ search/xxxhash.json ├─ category/xxxhash.json └─ detail/xxxhash.json

第五层:上游源站(原始数据源,最底层回源)

只有客户端缓存、本地 L1、Redis L2、磁盘 L3 四层全部失效 / 过期,才会发起网络请求爬取 RARBG 镜像源、第三方种子 API。 取回数据后自底向上回填所有上层缓存(磁盘→Redis→本地内存),完成一轮缓存刷新。

完整请求时序(对照分层理解)

  1. 用户请求 → 浏览器存在未过期(5min)Http 缓存 → 直接返回数据,结束
  2. 无浏览器缓存 → 请求到达服务端
  3. 读取进程本地 L1 内存缓存(5min 有效期)→ 命中直接响应
  4. L1 过期 / 不存在 → 查询 Redis L2 分布式缓存(标准 5min)→ 命中,同时回填 L1 内存缓存并返回
  5. Redis 无数据 → 校验磁盘 L3 文件是否在 5 分钟有效期内 → 读取磁盘数据,回填 Redis+L1 后返回
  6. 磁盘无有效数据 → 发起爬虫回源拉取真实数据
  7. 回源成功:数据落地磁盘 → 写入 Redis → 写入本地 L1 内存 → 响应客户端
  8. 回源失败:直接返回磁盘过期兜底数据,保障服务可用

分层价值总结(为什么要用多层,不是只做一个 Redis 5min 缓存)

  1. 浏览器缓存:削减外网请求量
  2. 本地 L1 内存:干掉 Redis 网络开销,极致压低接口 RT
  3. Redis L2:集群统一缓存、标准化 5 分钟时效管控,流量削峰、保护爬虫源站 IP
  4. 磁盘 L3:故障降级兜底,提升服务稳定性
  5. 五层逐级拦截,绝大多数请求都会停留在前三层,极少流量穿透到最底层的源站爬虫接口