面试官:在高并发场景下,你是如何保证数据的一致性和可靠性的?
最近帮粉丝看简历发现一个重灾区。很多同学简历上赫然写着“精通高并发”、“熟悉分布式架构”。结果面试官微微一笑抛出一个经典必问“在高并发场景下你是如何保证数据的一致性和可靠性的”很多同学脑子一热条件反射就开始背八股文“简单啊加分布式锁”“先写库再删缓存”“实在不行用延时双删”这时候面试官的连环炮就来了“延时双删里的 sleep 时间你怎么定靠猜吗”“如果删缓存的动作失败了MQ挂了数据不就不一致了吗”“微服务之间跨库怎么保证事务一致性难道你要用 2PC”这一通问下来你支支吾吾半天答不上来。这就是你简历上写的“精通”今天 Fox 老师带你拆解这个面试“修罗场”把这层窗户纸彻底捅破01 核心矛盾一场“殊死搏斗”首先把你的思维从“码农”升级到“架构师”。在高并发系统里核心矛盾到底是什么 答案是性能Performance与一致性Consistency的死磕。根据CAP 理论你想要高可用Availability和分区容错性Partition tolerance往往就得牺牲强一致性。所以把这句话刻在脑子里绝大多数高并发业务场景我们要追求的根本不是不切实际的“强一致性”而是更具弹性的“最终一致性”。02 第一层缓存与数据库的“双重奏”我们先看最基础的战场Cache Aside Pattern旁路缓存模式。 读请求很简单缓存没命中就查库查完回写缓存。 真正让无数人翻车的是写请求1. 更新缓存还是删除缓存有人说“老师更新缓存效率高啊不用下次再查库了。”错大错特错 Tell me why? 假设线程 A 和 B 并发写库。A 先写库值1B 后写库值2。 但因为网络抖动等原因B 先更新了缓存A 后更新了缓存。结果 数据库是新的2缓存却是旧的1。 这就是典型的脏数据所以在高并发写场景下必须删除缓存让下一次读请求去回填。2. 先删缓存还是后删缓存那有人又抖机灵了“那我先删缓存再写数据库总行了吧”这叫倒行逆施后果更严重 来看这个场景线程 A 删了缓存还没来得及写库。线程 B 来了发现缓存空了去读库读到了旧数据。线程 B 把旧数据塞回缓存。线程 A 终于把新数据写入数据库。结果 哪怕 A 写库成功了缓存里永远躺着那个旧数据。这叫持久性的脏数据3. “延时双删”是解药吗江湖上流传着一招“延时双删”先删缓存 - 写库 - sleep 一会儿 - 再删缓存。这个 sleep 时间你怎么定睡久了系统吞吐量直接掉底睡短了覆盖不了数据库的主从同步延迟。我常说一句话“在生产环境的核心链路里写 Thread.sleep 的直接拉出去祭天”03 第二层架构师的答案 —— 异步解耦那到底怎么做才能既优雅又可靠答案是异步解耦构建基于 Binlog 的异步消息流。架构思路非常清晰业务代码只管写 MySQL其他的“脏活累活”别管。我们利用 Canal 或 Maxwell 这种组件把自己伪装成 MySQL 的从节点监听 MySQL 的 Binlog。一旦数据发生变动组件自动解析并发送消息到 MQKafka/RocketMQ。下游消费者收到消息去执行“删缓存”操作。为什么这才是满分答案 因为 MQ 有重试机制 如果删缓存失败了没关系MQ 会一直重试直到成功。 如果一直失败消息进入死信队列触发报警人工介入。这就是最终一致性的完美体现——系统虽然有短暂的延迟但数据终将一致且业务接口响应极快。04 第三层微服务下的“原子性”挑战难度升级如果是跨服务的场景呢比如“订单服务”下订单“库存服务”扣库存。千万别跟我说用** 2PC两阶段提交** XA/2PC 是同步阻塞的锁定资源时间太长。 谁在高并发系统里用 2PC谁就是系统的罪人终极方案RocketMQ 的“事务消息”。这是一套基于“半消息Half Message”的魔法发半消息订单服务先发一条消息给 MQ。注意此时消费者库存服务是不可见的消费不到。执行本地事务订单服务去写自己的数据库创建订单。Commit/Rollback本地事务成功告诉 MQ “提交”消费者这时候才能看到这条消息去扣库存。本地事务失败告诉 MQ “回滚”消息直接丢弃。那么问题又来了敲黑板 如果本地事务成功了但发送 Commit 的时候网络断了MQ 没收到怎么办RocketMQ 有个大杀器叫“事务回查Back-Check”机制。 MQ 发现这条半消息悬在半空很久了它会反过来问发送方订单服务“哎兄弟你刚才那笔事务到底成没成啊”这时候你去查查本地库如果订单在就补发 Commit如果不在就回滚。这就是系统的自我修复机制既保证了性能没有长锁又保证了数据绝对不丢05 总结别再死记硬背那些过时的八股文了。从“删缓存”的陷阱到 Binlog 异步解耦再到 RocketMQ 的事务消息我们在高并发下践行的架构思维其实只有三点可用性优先 (Availability First)接受软状态 (Accept Soft States)最终一致性兜底 (Eventual Consistency)这才是真正“精通高并发架构”该有的样子