保证缓存一致性
保证缓存一致性需要根据具体的需求来定:
1、对数据实时性有一定要求
对数据实时性有一定要求即数据库数据更新需要近实时查询到最新的数据,针对这种情况可采用延迟双删、Canal+MQ异步同步的方式。
2、对数据实时性要求不高
使用定时任务的方式定时更新缓存。
3、对数据实时性要求非常高
此类场景不适合用缓存,直接使用数据库即可。
注意:在使用缓存时不论采用哪种方式,如果没有特殊要求一定要对key加过期时间,即使一段时间缓存不一致当缓存过期后最终数据是一致的。
1. 什么是缓存一致性
缓存一致性是指确保缓存中的数据与数据库中的数据保持同步,特别是在数据更新、删除等操作后,避免缓存中保存过期或错误的数据。根据系统对实时性的要求,缓存一致性的方案可分为三类:对数据实时性有一定要求、对数据实时性要求不高、对数据实时性要求非常高。不同场景下采用的方案有所不同。
2. 解决方案
2.1 对数据实时性有一定要求
在这种场景下,系统对数据的实时性要求较高,但允许在短时间内缓存和数据库数据不一致。常见解决方案包括 延迟双删 和 Canal+MQ 异步同步。
2.1.1 延迟双删策略
延迟双删 是一种常用的缓存一致性策略,特别适用于更新操作。它的原理是:在更新数据库数据时,先删除缓存,然后更新数据库,最后再延迟一段时间再次删除缓存,以确保缓存中的数据与数据库一致。
流程:
- 删除缓存中的数据。
- 更新数据库中的数据。
- 延迟一段时间(如 500ms 或 1s),再次删除缓存中的数据,确保在高并发场景下,可能被写入缓存的旧数据再次被清除。
public void updateData(Long id, String newValue) {
// 第一次删除缓存
cache.delete(id);
// 更新数据库
database.update(id, newValue);
// 延迟双删,确保缓存最终一致
Thread.sleep(1000); // 延迟一段时间
cache.delete(id);
}
优点:通过延迟的第二次删除缓存,确保在高并发情况下不会出现缓存存储旧数据的问题。
缺点:延迟的时间不易把握,太短会无法解决并发问题,太长会增加缓存与数据库不一致的时间。
2.1.2 Canal + MQ 异步同步
Canal + MQ 是一种异步同步数据库变更的方式,通过监听数据库的 binlog(变更日志),将数据库更新操作异步推送到消息队列,然后再由消费者根据消息更新缓存。适合对缓存更新要求较高的场景,且不影响主业务流程的性能。
流程:
- Canal 监听 binlog:Canal 监听数据库的 binlog 日志,当数据库中有更新时,Canal 捕获到更新事件。
- 推送消息到 MQ:Canal 将捕获到的更新事件推送到消息队列(如 Kafka 或 RabbitMQ)。
- 消费者处理消息:缓存服务作为消息队列的消费者,接收到更新事件后,更新或删除缓存中的数据。
优点:
(1)实时性较好,异步处理不会阻塞主业务逻辑。
(2)通过 MQ 进行解耦,适合分布式场景。
缺点:
(1)系统架构复杂度增加,需要额外维护 Canal 和消息队列。
(2)消息丢失或延迟可能导致短时间内缓存不一致。
2.2 对数据实时性要求不高
当系统对数据的实时性要求较低,允许数据存在一定延迟,缓存和数据库可以在一段时间内不一致。这时,可以通过 定时任务 来保证缓存一致性。
2.2.1 定时任务更新缓存
定时任务是一种简单有效的缓存一致性方案,适用于对实时性要求不高的场景。定时任务可以定期从数据库中获取最新数据,并更新缓存中的数据。
流程:
- 设置定时任务,每隔一定时间(如 5 分钟、1 小时等)主动从数据库中获取最新的数据。
- 更新缓存,将最新的数据写入缓存,覆盖旧数据。
@Scheduled(fixedRate = 600000) // 每10分钟执行一次
public void refreshCache() {
List<User> updatedUsers = database.getAllUsers(); // 从数据库获取最新数据
for (User user : updatedUsers) {
cache.put(user.getId(), user); // 更新缓存
}
}
优点:
(1)简单易实现,系统复杂度较低。
(2)定时任务可控制缓存更新的频率,适用于数据变化不频繁的场景。
缺点:
(1)更新频率受定时任务的执行周期影响,数据存在一定延迟,无法实时更新。
(2)如果缓存的数据量较大,可能会导致定时任务的执行时间过长。
2.3 对数据实时性要求非常高
在某些业务场景下,数据的实时性要求非常高,不能容忍缓存中的数据与数据库有任何不一致。这种情况下,缓存无法很好地满足业务需求,建议直接使用数据库来保证数据的强一致性。
场景:
- 对数据强一致性有非常高的要求,如金融系统中的余额更新、库存系统中的商品数量更新。
- 在这些场景下,数据的正确性和实时性至关重要,缓存机制本身引入的延迟可能导致系统数据不一致问题。
解决方案:
- 直接使用数据库:在强一致性要求下,不使用缓存,直接查询数据库,确保数据的正确性和实时性。
- 分布式事务:如果系统是分布式架构,可以采用分布式事务(如两阶段提交、TCC 等)来保证数据的一致性。
3. 总结
不论采用哪种方案,都应注意缓存的过期策略,合理设置缓存的过期时间(TTL,Time to Live),以确保缓存最终与数据库一致。即使在短时间内缓存和数据库数据不一致,缓存到期后会自动失效,最终数据可以保证一致性。