Redis动态热点数据缓存策略设计
Redis动态热点数据缓存策略设计
1. 热点数据识别机制
1.1 计数器方式
@Service
public class HotDataCounter {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 访问计数
public void incrementCounter(String key) {
String countKey = "counter:" + key;
redisTemplate.opsForValue().increment(countKey, 1);
// 设置计数器过期时间,比如1小时
redisTemplate.expire(countKey, 1, TimeUnit.HOURS);
}
// 获取访问次数
public Long getCounter(String key) {
String countKey = "counter:" + key;
return (Long) redisTemplate.opsForValue().get(countKey);
}
}
1.2 LRU算法实现
public class LRUCache<K, V> extends LinkedHashMap<K, V> {
private final int capacity;
public LRUCache(int capacity) {
super(capacity, 0.75f, true);
this.capacity = capacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > capacity;
}
}
2. 动态缓存策略实现
2.1 基础缓存服务
@Service
public class DynamicCacheService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private HotDataCounter hotDataCounter;
// 热点阈值
private static final long HOT_THRESHOLD = 100;
// 获取数据
public Object getData(String key) {
// 增加访问计数
hotDataCounter.incrementCounter(key);
// 从缓存获取数据
Object value = redisTemplate.opsForValue().get(key);
if (value != null) {
return value;
}
// 从数据库获取数据
value = getFromDB(key);
// 判断是否为热点数据
if (isHotData(key)) {
// 热点数据设置较长的过期时间
redisTemplate.opsForValue().set(key, value, 1, TimeUnit.HOURS);
} else {
// 非热点数据设置较短的过期时间
redisTemplate.opsForValue().set(key, value, 5, TimeUnit.MINUTES);
}
return value;
}
// 判断是否为热点数据
private boolean isHotData(String key) {
Long count = hotDataCounter.getCounter(key);
return count != null && count > HOT_THRESHOLD;
}
}
2.2 定时任务更新策略
@Component
public class HotDataScheduler {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Scheduled(fixedRate = 300000) // 每5分钟执行一次
public void updateHotData() {
// 获取所有计数器
Set<String> counterKeys = redisTemplate.keys("counter:");
if (counterKeys == null) return;
// 更新热点数据过期时间
for (String counterKey : counterKeys) {
String dataKey = counterKey.substring("counter:".length());
Long count = (Long) redisTemplate.opsForValue().get(counterKey);
if (count != null && count > HOT_THRESHOLD) {
// 延长热点数据过期时间
redisTemplate.expire(dataKey, 1, TimeUnit.HOURS);
}
}
}
}
3. 多级缓存策略
3.1 本地缓存配合Redis
@Service
public class MultiLevelCache {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 本地缓存
private final LoadingCache<String, Object> localCache = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build(new CacheLoader<String, Object>() {
@Override
public Object load(String key) {
return getFromRedis(key);
}
});
public Object get(String key) {
try {
return localCache.get(key);
} catch (ExecutionException e) {
return getFromRedis(key);
}
}
private Object getFromRedis(String key) {
Object value = redisTemplate.opsForValue().get(key);
if (value == null) {
value = getFromDB(key);
if (value != null) {
redisTemplate.opsForValue().set(key, value);
}
}
return value;
}
}
4. 热点数据预加载
4.1 预热服务
@Service
public class HotDataPreloader {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@PostConstruct
public void preloadHotData() {
// 从统计数据中获取历史热点数据
List<String> historicalHotKeys = getHistoricalHotKeys();
// 预加载数据到Redis
for (String key : historicalHotKeys) {
Object value = getFromDB(key);
if (value != null) {
redisTemplate.opsForValue().set(key, value, 1, TimeUnit.HOURS);
}
}
}
}
5. 缓存更新策略
5.1 更新服务
@Service
public class CacheUpdateService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 更新缓存数据
@Transactional
public void updateData(String key, Object value) {
// 更新数据库
updateDB(key, value);
// 判断是否为热点数据
if (isHotData(key)) {
// 直接更新缓存
redisTemplate.opsForValue().set(key, value, 1, TimeUnit.HOURS);
} else {
// 删除缓存
redisTemplate.delete(key);
}
}
}
6. 监控和告警
6.1 监控服务
@Service
public class CacheMonitorService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 监控缓存命中率
public double getHitRate() {
Long hits = (Long) redisTemplate.opsForValue().get("cache:hits");
Long misses = (Long) redisTemplate.opsForValue().get("cache:misses");
if (hits == null || misses == null) {
return 0.0;
}
return (double) hits / (hits + misses);
}
// 记录缓存访问
public void recordAccess(boolean isHit) {
String key = isHit ? "cache:hits" : "cache:misses";
redisTemplate.opsForValue().increment(key, 1);
}
}
7. 配置管理
7.1 动态配置
@Configuration
@RefreshScope
public class CacheConfig {
@Value("${cache.hot.threshold:100}")
private long hotThreshold;
@Value("${cache.hot.expire:3600}")
private long hotExpireSeconds;
@Value("${cache.normal.expire:300}")
private long normalExpireSeconds;
}
8. 总结
-
热点识别:
- 使用计数器记录访问频率
- 实现LRU算法管理缓存
-
动态缓存:
- 根据访问频率动态调整过期时间
- 定时任务更新热点数据
-
多级缓存:
- 本地缓存配合Redis
- 减少网络开销
-
预加载机制:
- 系统启动时预加载历史热点数据
- 提高系统启动后的访问性能
-
更新策略:
- 热点数据直接更新缓存
- 非热点数据采用删除策略
-
监控告警:
- 监控缓存命中率
- 记录访问统计
-
配置管理:
- 支持动态调整配置
- 灵活控制缓存策略