在分布式系统中,Redis作为缓存与数据库协同工作时,数据一致性是高频面试题。以下从核心场景分析、解决方案及优化策略展开说明:
一、数据不一致的核心场景
读写并发
纯读操作:仅查询不会导致不一致。
读写并发:当修改数据(写)与查询数据(读)同时发生时,若操作顺序不当,缓存与数据库数据可能不一致。
二、写策略选择:删除缓存 vs 更新缓存
直接删除缓存的优势
逻辑简单:仅需删除缓存,后续请求触发被动加载数据库最新数据。
避免复杂计算:更新缓存可能涉及业务逻辑处理(如聚合统计),删除操作更轻量。
规避多线程竞争:并发更新缓存可能导致数据覆盖或脏数据。
更新缓存的弊端
数据耦合风险:缓存层与业务逻辑耦合度高,维护成本增加。
资源浪费:高频更新但低频访问的数据频繁写入缓存,占用内存。
三、操作顺序:先操作数据库 vs 先操作缓存
方案1:先删缓存,再更新数据库(延迟双删)
问题场景:
线程A删除缓存后更新数据库(网络延迟),线程B查询旧数据并回填缓存,导致后续请求读取到旧数据。解决方案:延迟双删
线程A删除缓存 → 更新数据库 → 延迟数百毫秒 → 再次删除缓存。
延迟目的:确保线程B的旧数据回填已完成,二次删除清空脏数据。
缺点:短暂数据不一致窗口,需业务容忍最终一致性。
方案2:先更新数据库,再删缓存
优势:
线程A先更新数据库后删缓存,线程B查询时触发缓存重建,数据一致性更高。极端问题:若缓存删除失败,需通过重试机制保证最终一致。
四、优化策略:解耦与异步保障
重试机制
MQ异步重试:删除缓存失败时,发送消息至MQ,消费者监听并重试删除。
本地重试表:记录失败操作,定时任务扫描重试。
基于Binlog的最终一致性(Canal监听)
Canal原理:模拟MySQL主从复制,解析Binlog日志获取数据变更。
流程:
数据库更新 → Canal捕获变更 → 通知客户端(如Spring Boot应用)。
客户端收到通知 → 删除或更新Redis。
优势:业务代码解耦,通过中间件保证数据同步。
五、一致性的权衡:AP vs CP
强一致性(CP):通过分布式锁保证操作原子性,但牺牲性能,不适用于高并发场景。
最终一致性(AP):接受短暂不一致,通过延迟双删、异步监听等手段实现最终一致,适用于大多数业务场景。
六、总结回答
在面试中可结构化回答:
问题分析:读写并发是导致不一致的主因。
策略选择:推荐先更新数据库再删缓存,结合延迟双删。
容错机制:通过MQ重试或Canal监听Binlog解耦处理。
业务权衡:根据场景选择最终一致性,平衡性能与数据准确性。
最佳回答:
"在高并发场景下,我们采用‘先更新数据库,再删除缓存’策略,并结合延迟双删避免并发读写导致的不一致。针对极端删除失败情况,通过Canal监听Binlog异步触发缓存删除,或MQ重试机制保证最终一致。这种方案在保证系统性能的同时,最大限度减少数据不一致窗口期。"
评论区