你有没有遇到过这种情况:打开一个购物App,商品列表刷一下就出来了,可刚点进去详情页,却要转半天才加载出来?其实这背后很可能就是缓存机制没设计好。合理的缓存能让系统快得飞起,不合理的反而拖慢性能,甚至出错。
先想清楚:缓存什么
不是所有数据都适合缓存。频繁读、很少写的才值得放进去。比如天气预报,一天更新一次,但被成千上万人查,这种就很适合。而用户购物车这种每个人都不一样、还经常变动的,就得小心处理,不然容易看到别人的东西,那就尴尬了。
选对存储位置
缓存可以放在内存里,比如用Redis或者本地Map。Redis适合多机器共享,本地内存快但没法共用。如果只是单机服务,而且数据量不大,用ConcurrentHashMap就能搞定。比如记录某个接口一分钟内被调了多少次,防刷限流用的,放本地完全没问题。
private static final Map<String, Long> cache = new ConcurrentHashMap<>();
public String getData(String key) {
if (cache.containsKey(key)) {
return cache.get(key);
}
// 从数据库查
String dbData = queryFromDB(key);
cache.put(key, dbData);
return dbData;
}
设置合适的过期时间
缓存不能一直留着。新闻首页的内容,两分钟刷新一次比较合适。用户头像可能几天都不会变,可以缓存更久。但要是账号被封了,头像还得立刻下架,这时候就得主动清除缓存,不能干等它自己过期。
别忘了异常情况
缓存挂了怎么办?比如Redis连不上。这时候可以考虑“降级”策略——直接查数据库,虽然慢点,但至少还能用。也可以在代码里加个开关,紧急时刻干脆绕开缓存,避免雪崩。
小心缓存穿透和击穿
有人故意查一堆不存在的数据,每次都没命中,请求全打到数据库上,这就是缓存穿透。解决办法之一是把“这个key没数据”也记下来,比如存个null值,设短一点的过期时间,防止恶意攻击。
热点数据突然过期,瞬间大量请求涌进来,叫缓存击穿。可以用互斥锁,让第一个请求去查数据库,别的等着,等新值放进缓存后再一起返回。
监控和清理同样重要
上线后得盯着缓存命中率。如果发现大部分请求都没命中,那可能设计有问题,要么是过期太短,要么是key设计得不合理。另外定期清理旧数据,别让缓存越积越大,把内存撑爆。
缓存不是加了就万事大吉,它更像是一个需要经常调教的工具。什么时候该用,用多久,怎么应对意外,每个环节都得考虑到。设计得好,系统稳如老狗;设计不好,可能比不用还麻烦。