跳到主要内容

本地缓存实现与应用

本地缓存架构设计

什么是本地缓存

本地缓存是指与应用服务器部署在同一JVM进程内的缓存组件,将热点数据存储在应用程序的堆内存中,通过消除网络调用开销,实现微秒级的数据访问速度。相比分布式缓存,本地缓存的访问延迟可降低100倍以上。

核心设计要素

实现一个高质量的本地缓存需要解决以下关键问题:

数据结构选型

采用键值对(Key-Value)结构是业界共识,既要保证查询效率,又要支持高并发访问:

线程安全保障

本地缓存通常是全局单例对象,会被多个业务线程并发访问。必须采用线程安全的数据结构,如ConcurrentHashMap,或通过锁机制保护临界区。

容量限制管理

JVM堆内存有限,必须严格控制缓存容量上限,防止内存溢出:

// 设置缓存最大容量为10000个条目
Cache<String, UserInfo> userCache = Caffeine.newBuilder()
.maximumSize(10000)
.build();

淘汰策略配置

当缓存达到容量上限时,通过淘汰算法选择移除的数据。常见策略包括:

  • LRU(最近最少使用): 淘汰最久未访问的数据
  • LFU(最少频次使用): 淘汰访问次数最少的数据
  • FIFO(先进先出): 淘汰最早加入的数据
  • 软引用/弱引用: 在GC压力下自动回收

过期时间设置

双重保障机制确保数据及时更新:

Cache<String, ProductInfo> productCache = Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES) // 写入后10分钟过期
.expireAfterAccess(5, TimeUnit.MINUTES) // 最后访问后5分钟过期
.build();

实现方案对比

基于HashMap的基础实现

最简单的方案是使用ConcurrentHashMap:

public class SimpleLocalCache {

private final ConcurrentHashMap<String, CachedObject> cache;

public SimpleLocalCache() {
this.cache = new ConcurrentHashMap<>();
}

/**
* 存储数据到缓存
*/
public void put(String key, Object value, long ttlSeconds) {
CachedObject cachedObj = new CachedObject(
value,
System.currentTimeMillis() + ttlSeconds * 1000
);
cache.put(key, cachedObj);
}

/**
* 从缓存获取数据
*/
public Object get(String key) {
CachedObject cachedObj = cache.get(key);
if (cachedObj == null) {
return null;
}

// 检查是否过期
if (System.currentTimeMillis() > cachedObj.getExpireTime()) {
cache.remove(key);
return null;
}

return cachedObj.getValue();
}

/**
* 缓存对象包装类
*/
private static class CachedObject {
private final Object value;
private final long expireTime;

public CachedObject(Object value, long expireTime) {
this.value = value;
this.expireTime = expireTime;
}

public Object getValue() {
return value;
}

public long getExpireTime() {
return expireTime;
}
}
}

优点: 实现简单,无外部依赖

缺点: 需要手动实现容量控制、过期清理、淘汰策略等功能,生产环境不推荐

主流开源框架选型

框架性能功能丰富度推荐指数
Caffeine⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Guava Cache⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Ehcache⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐

Caffeine最佳实践

Caffeine是Spring 5官方推荐的本地缓存方案,性能卓越: