标准答案
- 读取时先判断 expiresAt,过期就删除并返回未命中。
- 超过最大容量时按 LRU、LFU 或近似策略淘汰,不能把过期数据当作有效容量。
- 定期扫描或维护过期队列做主动清理,并让并发读写有明确同步边界。
题目解析
TTL 表达某条数据何时不再有效,最大容量淘汰表达内存不足时先删除谁,两者不能互相替代。一个 Key 即使 TTL 很长,也可能在内存压力下先被淘汰。
惰性清理只在访问时发现过期 Key,冷 Key 可能长期占用空间,因此要配合定期扫描、过期队列或存储自身的主动过期。扫描也要有批量和时间上限,避免清理任务阻塞主路径。
并发读写要明确 Map、淘汰链表和过期状态的同步边界。淘汰策略还应结合热点、对象大小和业务重建成本,不能只追求命中率。
代码示例
缓存项的核心判断:
TypeScript
const item = map.get(key)
if (!item || item.expiresAt <= clock.now()) {
map.delete(key)
return undefined
}
return item.value常见误区
- 误区:为每个 Key 创建独立 setTimeout。改正:大规模缓存使用惰性加批量主动清理,避免定时器数量失控。
- 误区:过期读取不删除。改正:返回未命中的同时删除或标记过期,容量统计不能把无效项算作有效缓存。
- 误区:淘汰策略没有说明并发和热点影响。改正:说明锁、近似 LRU/LFU、对象大小和热点重建成本。