为对象存储读缓存设计混合 LRU+TTL 淘汰策略:平衡热点留存与过期清理
面向 S2 StreamStore 的 Cachey,设计 LRU 与 TTL 组合的缓存淘汰策略,提供可落地的参数配置与监控清单,提升缓存命中率并避免污染。
在构建面向对象存储(如 S3)的高性能读缓存时,一个核心挑战是如何在有限的缓存空间内,既高效地保留访问频率最高的“热点”数据,又及时清理那些已过期或即将过期的“垃圾”数据。单一的淘汰策略往往难以兼顾这两点:纯粹的 LRU(最近最少使用)算法虽然能很好地保留热点,但对已过期数据无能为力,可能导致缓存被大量无效数据占据;而纯粹的 TTL(生存时间)策略虽然能保证数据新鲜度,却无法区分数据的访问热度,可能在高峰期将热点数据过早驱逐。为了解决这一矛盾,我们为 S2 StreamStore 的核心组件 Cachey 设计了一套混合 LRU+TTL 淘汰策略。这套策略并非简单的功能叠加,而是通过精心设计的参数和监控体系,实现两者的动态平衡,最终目标是最大化缓存命中率,同时最小化后端存储的穿透压力。
Cachey 作为一个专为对象存储设计的读穿透缓存,其架构天然支持分层存储(内存 + 磁盘),并依赖底层的 foyer
库来管理缓存页。虽然 foyer
本身是一个高性能的 Rust 缓存引擎,但其默认或文档化的淘汰策略细节并未在公开资料中完全阐明。这为我们提供了定制化设计的空间。借鉴业界成熟实践,如 Redis 中 volatile-lru
和 volatile-ttl
策略的组合思想,我们可以为 Cachey 构建一个更智能的混合模型。其核心思想是:在缓存淘汰的决策过程中,同时考虑数据的“热度”(由 LRU 机制评估)和“新鲜度”(由 TTL 机制评估)。具体而言,当缓存空间紧张需要驱逐数据时,系统应优先淘汰那些既不“热”(LRU 评分低)又“旧”(TTL 即将到期或已过期)的数据项。这种双重筛选机制能有效避免单一策略的缺陷。例如,一个访问频率极高的热点视频片段,即使其 TTL 设置较长,也不应被轻易淘汰;反之,一个访问次数寥寥且 TTL 即将到期的临时日志文件,则应被优先清理。
要将这一理论转化为工程实践,关键在于定义一组可配置、可监控的参数。首先,是 TTL 的设置。TTL 不应是一个全局固定的值,而应允许根据 kind
(即数据类别)进行差异化配置。例如,对于高频访问的“prod-videos”类别,可以设置较长的 TTL(如 7 天),以确保热门内容的长期驻留;而对于低频访问的“temp-logs”类别,则应设置较短的 TTL(如 1 小时),加速其清理。其次,是 LRU 的实现参数。鉴于 Cachey 面向高并发场景,采用精确 LRU 的开销过大,应借鉴 Redis 的近似 LRU 算法,通过配置 lru_sample_size
(如 5 或 10)来控制每次淘汰时的采样精度,在 CPU 开销和淘汰准确性之间取得平衡。第三,是资源配额。必须为内存和磁盘缓存分别设置硬性上限(如 --memory 4GiB
和 --disk-capacity 100GiB
),这是触发淘汰策略的前提。最后,也是最重要的,是监控指标。必须暴露 cache_hit_ratio
(缓存命中率)、expired_keys_evicted
(因过期被淘汰的键数)和 lru_evicted_keys
(因 LRU 被淘汰的键数)等核心指标。这些指标是策略是否有效的直接反馈。例如,如果 expired_keys_evicted
持续为 0,说明 TTL 设置过长或数据本身无过期需求;如果 cache_hit_ratio
下降而 lru_evicted_keys
激增,则可能意味着采样精度不足或内存配额过小,导致热点数据被误伤。
当然,任何策略都有其风险和局限。混合 LRU+TTL 策略的主要风险在于配置不当导致的“缓存污染”或“缓存击穿”。如果 TTL 设置过长,过期数据会长期占据缓存空间,挤压热点数据,这就是污染;如果 LRU 采样精度太低或内存配额太小,真正的热点数据可能在高峰期被误淘汰,导致大量请求穿透到后端对象存储,引发性能雪崩,这就是击穿。为了规避这些风险,我们建议实施严格的灰度发布和 A/B 测试。新策略不应直接在生产环境全量上线,而应先在一个小比例的流量或副本上进行验证,通过对比新旧策略下的 cache_hit_ratio
和后端存储的 QPS 变化,来评估其真实效果。此外,必须建立告警机制。当 cache_hit_ratio
低于某个阈值(如 85%)或 lru_evicted_keys
的瞬时速率异常飙升时,应触发告警,通知运维人员介入检查配置。一个稳健的兜底策略是,当混合策略因任何原因失效时,应能快速回滚到一个保守的、经过充分验证的单一策略(如纯 LRU),以保证服务的可用性。总而言之,混合 LRU+TTL 策略是提升对象存储缓存效率的一剂良方,但其成功完全依赖于精细化的参数调优和持续的监控反馈。它不是一个开箱即用的黑盒,而是一个需要工程师持续投入和打磨的精密系统。