FunTester API 缓存设计指南

FunTester · 2026年07月23日 · 29 次阅读

API 缓存的核心,是把已经计算过的响应暂存在更靠近请求方的位置。后续出现相同或等价的请求时,系统直接返回缓存副本,无需再次访问数据库、下游服务或执行计算。它带来的不只是更短的响应时间,还包括更低的源站负载、更少的带宽消耗,以及流量高峰时更好的韧性。

缓存命中与未命中

缓存中存在仍然有效的副本时,称为缓存命中(cache hit);缓存中没有可用副本、请求必须回源获取数据时,称为缓存未命中(cache miss)。缓存命中率是衡量缓存效果的关键指标:命中率越高,越少请求需要进入昂贵的后端链路。

命中率的收益不是线性的。当缓存访问远快于回源访问时,命中率从较高水平继续提升,会明显拉低平均延迟。因此,缓存设计不能只看是否加了缓存,还要持续观察命中率和回源流量。

缓存层级

缓存通常不是单点能力,而是一组由近及远的层级:

  • 客户端缓存:浏览器或移动端依据 HTTP 响应头在本地保存结果,适合稳定的资源和参考数据,可直接省去网络往返。
  • CDN 边缘缓存:在靠近用户的节点返回公共内容,适合全球分布的访问场景。
  • API 网关缓存:位于公开 API 与后端服务之间,可统一 TTL 策略,并与限流等治理能力配合。
  • 应用进程内缓存:访问极快,适合配置、热点字典等,但不在多个应用实例间共享。
  • 分布式缓存:例如 Redis、Memcached,为多个实例提供共享缓存,是生产系统中常见的骨干层。
  • 数据库查询缓存:由数据库内部维护,可作为补充,但对失效和策略的可控性相对较弱。

实践中,通常会组合使用多层缓存:静态内容优先由客户端或 CDN 命中,服务内部热点数据放入本地缓存,需要跨实例共享的数据再由分布式缓存承接。每一层都处理最适合自己的请求,尽量让真正无法缓存的请求才到达源站。

常见缓存策略

策略 工作方式 适用场景与代价
Cache-aside(旁路缓存) 应用先查缓存,未命中时回源并写入缓存 最常见,适合读多写少;冷启动或清缓存后会出现较多未命中。
Write-through(写穿) 每次写入同时更新源数据和缓存 读己之写要求强的数据;写延迟更高。
Write-behind / Write-back(异步回写) 先写缓存,再异步落库 写吞吐高,但缓存故障时存在尚未落库数据丢失的风险。
Read-through(读穿) 缓存层在未命中时自行回源加载 简化应用代码,但缓存层需要具备足够容量和可用性。
Stale-while-revalidate(过期即返回,后台刷新) 过期条目先返回旧值,同时异步刷新 对低延迟敏感、可容忍短暂陈旧数据的公共接口。

选择策略时,先回答四个问题:数据能陈旧多久,写入后是否必须立即可见,故障时能否接受少量丢失,以及哪些读路径值得用复杂度换取性能。

TTL 与缓存失效

TTL(Time to Live,存活时间)定义一条缓存数据在多长时间内可被视作新鲜数据。TTL 太短会造成频繁回源,缓存价值有限;TTL 太长则可能让用户读到过期信息。

合理做法是按数据的变化速度分别设定 TTL,而不是给全系统套用一个数值。例如,几乎不变的静态资源可使用较长 TTL;搜索结果、价格和聚合统计通常需要更短 TTL;认证、结算和支付等敏感接口通常不应进入共享缓存。

仅依靠 TTL 的问题是:源数据更新后,旧缓存会一直存在到自然过期。对一致性要求较高的场景,可以采用事件驱动失效:订单或商品数据更新时,发布事件并主动清除或更新相关缓存。CDN 场景还可以用代理键(surrogate key)把多个相关响应关联起来,实现按业务实体批量清除。

防止缓存雪崩与击穿

热点键同时过期时,许多并发请求会一起回源,造成短时间内大量重复查询,这就是常说的惊群或缓存击穿风险。常见缓解手段包括:

  • 在部署或清缓存后预热关键热点数据。
  • 对同一键合并并发回源请求,避免重复加载。
  • 给 TTL 加入轻微随机抖动,避免大量键同步失效。
  • 为非强一致的接口采用 stale-while-revalidate,在刷新期间继续提供旧数据。

HTTP 缓存语义

HTTP 自带的缓存协议是 API 缓存的重要基础。Cache-Control 中的 max-age 表示新鲜期;public 允许 CDN 等共享缓存保存响应;private 限制为终端客户端缓存;no-store 禁止任何缓存;no-cache 则允许保存,但使用前必须向源站重新验证。

ETag 和 Last-Modified 支持条件请求。缓存过期后,客户端可以携带已有的验证信息请求源站;如果资源没有变化,源站返回 304 Not Modified,无需重传完整响应体。这在保持新鲜度的同时减少了带宽与计算开销。

共享缓存禁区

缓存错误往往比不缓存更危险。个性化数据必须使用用户维度的缓存键,且不能泄露到共享缓存;余额、实时库存等数据应使用很短的 TTL,或干脆避免缓存;认证令牌、会话信息不能存入共享缓存;结算和支付响应更不应缓存,因为它们往往是非幂等操作,错误复用可能导致重复扣款或重复下单。

关键监控指标

至少应监控缓存命中率、未命中率、淘汰率、各接口的未命中分布,以及缓存对源站流量的削减比例。命中率持续偏低,常见原因是 TTL 过短、缓存键拆分得过细,或缓存容量不足导致频繁淘汰。命中率很高却不断收到数据过期投诉,通常说明 TTL 对这类数据设置得过长。

还要观察未命中是否集中发生在同一时段。若集中出现,可能是大量键同时到期,需要用 TTL 抖动、预热或请求合并来处理。


相关阅读

##### FunTester 名片|万粉千文,百无一用

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册