面试题答案
一键面试可能引发数据不一致的情况
- 缓存更新策略不当:
- 先更新数据库,再删除缓存:在高并发场景下,可能存在线程A更新数据库后,还未来得及删除缓存,此时线程B读取数据,从缓存中获取到旧数据,然后线程A删除缓存,线程B又将旧数据写入缓存,导致缓存与数据库数据不一致。
- 先删除缓存,再更新数据库:如果在删除缓存后,更新数据库操作失败,而其他线程读取数据时发现缓存缺失,就会从数据库读取旧数据并写入缓存,造成缓存与数据库数据不一致。
- 主从复制延迟:MySQL采用主从复制架构时,主库数据更新后同步到从库存在一定延迟。若在从库同步完成前,读取数据并写入Redis,就可能将旧数据写入Redis,导致Redis与主库数据不一致。
解决方案
- 缓存更新策略优化:
- 双删策略:先删除缓存,更新数据库,然后延迟一定时间再次删除缓存。延迟时间根据业务情况调整,确保其他线程有足够时间从数据库读取新数据并更新缓存。示例代码(以Java为例):
public void updateData(String key, Object data) {
redisTemplate.delete(key);
// 更新数据库操作
updateDatabase(data);
try {
Thread.sleep(500); // 延迟500毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
redisTemplate.delete(key);
}
- **使用队列**:将缓存更新操作放入队列,按顺序执行,避免并发冲突。以RabbitMQ为例,先将更新操作发送到队列,消费者从队列中取出操作依次执行,先删除缓存再更新数据库。
2. 处理主从复制延迟: - 强制读主库:对于实时性要求高的数据读取操作,直接从主库读取数据,确保获取到最新数据后再写入Redis。可以在代码层面通过配置数据源切换,例如在Spring Boot中,可以通过自定义数据源路由规则实现。 - 缓存失效时间设置:合理设置Redis缓存的失效时间,在主从复制延迟期间,若缓存失效,再次读取时从主库获取最新数据并更新缓存。如:
redisTemplate.opsForValue().set(key, value, 300, TimeUnit.SECONDS); // 设置缓存300秒失效