redis与数据库的数据同步
redis与数据库的数据同步
Redis 和 数据库 一致性问题是企业级应用中常见的挑战之一,特别是在高并发、高可用的场景下。由于 Redis 是内存型数据库,具备极高的读写速度,而 作为持久化的数据库,通常用于数据的可靠存储,如何保证两者数据的一致性需要具体业务场景的设计与优化。
1.先更新数据库再更新缓存
场景:
在大部分业务系统中,Redis 作为缓存层用于提升系统的读取性能,而 数据库 作为持久化存储,用于保证数据的可靠性。最常见的场景是:
系统先查询 Redis 缓存,如果缓存中没有数据,再从 数据库 中查询并将数据写入 Redis 缓存。
更新数据时,更新数据库 并删除 Redis 缓存,使缓存数据失效,保证下次读取时能拿到最新数据。
如何保障一致性:
1)缓存淘汰策略:数据库 数据更新后立即删除 Redis 缓存,确保下次读取时能获取到最新数据。即通过 "删除缓存" 的方式避免脏数据存在于缓存中。
2)并发问题:当并发请求较高时,可能会出现“缓存雪崩”或“缓存击穿”问题。例如:A 更新数据库 数据,B 在缓存失效的瞬间读取了旧数据,再次缓存到 Redis。为解决此问题,可以采用 延迟双删策略:
删除 Redis 缓存。
更新 数据库L。
适当延迟(如 500ms),再次删除 Redis 缓存,确保在并发情况下不存在缓存不一致问题。
演示代码:
// 更新商品详情的伪代码 public void updateProduct(Product product) { // 1. 更新数据库 updateProductInMySQL(product); // 2. 删除缓存 deleteProductCache(product.getId()); // 3. 延迟双删,解决并发下不一致问题 try { Thread.sleep(500); // 可以根据实际业务场景调整 } catch (InterruptedException e) { // handle exception } deleteProductCache(product.getId()); }
2.先更新缓存再更新数据库
场景:
在某些实时性要求较高的场景中,可以考虑先更新 Redis 缓存,然后再异步更新 数据库。
典型业务场景:
秒杀系统:例如商品库存的扣减,用户购买商品时,首先更新 Redis 中的库存数量,保证极低延迟的实时性体验。然后将变更异步写入数据库,确保持久化存储的一致性。
方案分析:
读取路径:读取 Redis 缓存的库存信息,能够提供快速的读取响应。
写入路径:更新 Redis 中的库存数量后,使用消息队列或其他异步机制将更新同步到 数据库。
如何保障一致性:
数据最终一致性:Redis 作为前端实时数据的缓存,数据库 作为后端数据的持久化存储,采用异步更新策略时,一致性无法保证是强一致性,但可以通过使用消息队列等手段来保证最终一致性。异步写入数据库 时,如果操作失败,可以通过重试机制或补偿机制恢复一致性。
演示代码:
// 扣减库存的伪代码 public void reduceStock(Long productId, int amount) { // 1. 先更新 Redis 中的库存 redisTemplate.decrement("stock:" + productId, amount); // 2. 通过消息队列异步更新 数据库 中的库存 sendUpdateStockMessage(productId, amount); } // 消费消息队列更新 数据库 @RabbitListener(queues = "stock_update_queue") public void updateStockInMySQL(UpdateStockMessage msg) { // 从 数据库 中扣减库存 productRepository.reduceStock(msg.getProductId(), msg.getAmount()); }
一致性保证策略:
-
幂等性保障:确保消息的处理是幂等的,即相同的消息即使被处理多次,也不会导致库存重复扣减。
-
消息重试机制:如果消费消息时更新 数据库 失败,可以设置重试机制或消息补偿机制,保证最终数据一致性。
3. 双写操作(缓存与数据库同时更新)
场景:
有时业务需要同时更新 Redis 和 数据库的数据,如用户余额更新、积分奖励系统等场景中,Redis 和 数据库 需要同步写入。
方案分析:
-
同步写入:当更新用户积分时,Redis 和 数据库 同时更新数据。由于需要保证两个存储的同步性,必须考虑事务性问题。
-
分布式事务:如果系统架构分布式,可能需要使用分布式事务(如
2PC,或者更轻量的解决方案如TCC)来确保一致性。
如何保障一致性:
双写一致性问题:如果同时写 Redis 和 数据库,可能会面临一致性问题。常见解决方案是通过事务补偿机制来实现。具体步骤:
1)使用数据库事务保证 数据库写入成功。
2)如果 Redis 写入失败,可以尝试重试,或在事务结束后通过补偿机制将失败的数据写入 Redis。
事务性保障:
本地事务:在单体系统中,可以依赖数据库事务和 Redis 的操作保证一致性。如果操作失败,通过重试机制来恢复一致性。
分布式事务:在微服务架构中,双写操作涉及分布式事务,可能需要使用 TCC(Try, Confirm, Cancel)等模式,或使用消息队列进行最终一致性补偿。
4. 数据回写(Write Back)策略
场景:
数据回写模式适用于 Redis 作为缓存层,数据库 作为持久化存储层,但 Redis 中数据修改后并不立即同步更新数据库,而是在特定时机触发数据回写。
典型业务场景:
广告计费系统:广告点击量保存在 Redis 中,以减少频繁的数据库写入压力,定期将 Redis 中的统计数据批量写入数据库。
方案分析:
延迟回写:可以通过定时任务或者触发器将 Redis 中的数据定期回写到数据库,这样既减少了 数据库 的压力,又保证了数据一致性。
如何保障一致性:
持久化与批量同步:通过 Redis 的持久化机制(如 RDB、AOF),在 Redis 崩溃时不会丢失数据。通过定时器或事件驱动系统触发批量同步 数据库。
本文来自博客园,作者:{咏南中间件},转载请注明原文链接:https://www.cnblogs.com/hnxxcxg/p/18912540

浙公网安备 33010602011771号