缓存失效为何总出问题
在做WiFi覆盖系统时,经常遇到设备状态更新延迟的情况。比如用户重启了路由器,管理后台却还显示在线,排查到最后发现是缓存没及时失效。这类问题背后,往往是缓存失效策略设计不当导致的。
缓存未及时删除
最常见的问题是数据变了但缓存还在。比如AP(接入点)的位置信息更新了,接口查的却是Redis里老的数据。这种情况多发生在删除缓存这一步被遗漏,或者异步任务失败后没有重试机制。
解决办法是在数据库更新后,主动删除对应key。例如:
// 更新数据库后删除缓存
db.updateAccessPoint(newInfo);
redis.delete("ap:detail:" + newInfo.id);先删缓存还是先改数据库
顺序不对也会出事。如果先删缓存再改数据库,中间刚好有请求进来,就会把旧数据重新写回缓存,造成短暂不一致。反过来,先改库再删缓存,虽然理论上也有窗口期,但风险更小。
更稳妥的做法是在更新数据库后加一个短暂延迟双删,比如:
db.updateApStatus(apId, "offline");
redis.delete("ap:status:" + apId);
// 延迟1秒再次删除,防止期间被误加载
Thread.sleep(1000);
redis.delete("ap:status:" + apId);缓存穿透:查不存在的数据
恶意请求或逻辑错误导致频繁查询一个根本不存在的AP ID,每次都会打到数据库。缓存层没有做拦截,数据库压力陡增。
可以在缓存中对这类“空结果”也设个短过期标记,比如:
String result = redis.get("ap:detail:" + id);
if (result == null) {
Ap ap = db.findApById(id);
if (ap == null) {
// 设置空值,防止穿透
redis.setex("ap:detail:" + id, 60, "nil");
} else {
redis.set("ap:detail:" + id, toJson(ap));
}
}雪崩效应怎么防
如果大量缓存同时过期,比如给所有AP状态统一设了1小时过期,时间一到,数据库瞬间被几百个请求压垮。这种场景下应该让过期时间加个随机偏移。
比如原本设3600秒,改成3600 + random(1800)秒,错开失效时间。
本地缓存与分布式缓存不同步
有些服务为了提速用了本地缓存(如Caffeine),但忽略了和Redis之间的同步。一台机器更新了数据,其他节点依然拿着旧值,导致用户看到的WiFi信号强度和实际不符。
这时候需要引入消息通知机制,比如用MQ广播缓存变更事件,各节点收到后清掉本地副本。