跳到主要内容

缓存系统设计与预热策略

缓存系统设计要素

缓存是提升系统性能的关键技术,但设计一个健壮的缓存系统需要考虑多个维度。根据部署位置的不同,缓存分为本地缓存分布式缓存两大类,它们面临的挑战和解决方案各有不同。

本地缓存核心设计

数据结构选择

缓存的本质是空间换时间,通过在内存中存储热点数据来避免昂贵的IO操作。为实现O(1)的存取效率,通常采用Key-Value结构:

  • HashMap系列:基于哈希表实现,适合大多数场景
  • ConcurrentHashMap:线程安全的哈希表,适合多线程环境
  • 专用缓存库:如Caffeine、Guava Cache,提供更丰富的功能

线程安全保障

本地缓存通常作为全局共享资源,必须考虑并发访问安全:

// 不推荐:使用普通HashMap
private Map<String, Object> cache = new HashMap<>(); // 线程不安全

// 推荐方式一:使用ConcurrentHashMap
private Map<String, Object> cache = new ConcurrentHashMap<>();

// 推荐方式二:使用Caffeine
private Cache<String, Object> cache = Caffeine.newBuilder()
.maximumSize(10000)
.expireAfterWrite(Duration.ofMinutes(10))
.build();

优秀的缓存框架通常采用以下技术保证线程安全:

  • CAS操作:无锁更新计数器、统计数据等
  • 分段锁:将数据分成多个段,降低锁粒度
  • 读写分离:允许并发读,串行写

容量控制机制

本地缓存占用JVM堆内存,必须设置上限防止OOM:

// 方式一:限制条目数量
Cache<String, User> cache = Caffeine.newBuilder()
.maximumSize(10000) // 最多存储10000个条目
.build();

// 方式二:基于权重限制
Cache<String, byte[]> cache = Caffeine.newBuilder()
.maximumWeight(100 * 1024 * 1024) // 总权重不超过100MB
.weigher((key, value) -> value.length) // 以字节数组长度为权重
.build();

淘汰策略

当缓存达到容量上限时,需要淘汰部分数据。常见淘汰策略: