虾皮一面:如何保证数据双写一致?

小厂救火员
• 阅读 208

年关将至,又到了准备面试跳槽的季节了。据不完全统计,跳槽是涨薪最快的方式,没有之一。而跳槽成功与否的关键是“面试”,所以认真准备面试 = 快速涨薪。

准备面试,自然就少不了刷面试真题了,而今天这份刚出炉的虾皮 Java 后端面试题就非常典型,它的难度适中,面试结构分为:半小时八股 + 半小时手撕代码,是目前典型的大公司的面试方式,真题如下:
虾皮一面:如何保证数据双写一致?
面试问题很多,一篇文章肯定是写不完的(大部分面试题可以在我的网站上找到答案:www.javacn.site),咱们今天就拿里面最经典,最常见的面试题来聊一聊:如何保证缓存和数据库的双写一致性?

1.什么是双写一致性?

在分布式系统中,数据库和缓存会搭配一起使用,以此来保证程序的整体查询性能。

也就说,分布式系统为了缓解数据库查询的压力,会将查出来的数据保存在缓存中,下次再查询时,直接走缓存系统,而不再查询数据库,这样就极大的提高了整体的查询性能。

1.1 为什么缓存比数据库快?

缓存之所以比数据库快的主要原因有以下 3 点:

  1. 内存访问速度快:缓存通常将数据存储在内存中,而数据库将数据存储在磁盘上。相比于磁盘访问,内存访问速度更快,可以达到纳秒级别的读取速度,远远快于数据库的毫秒级别的读取速度。
  2. IO 操作次数少:数据库通常需要进行磁盘 IO 操作,包括读取和写入磁盘数据。而缓存将数据存储在内存中,避免了磁盘 IO 的开销。内存访问不需要进行磁盘寻址和机械运动,相对来说速度更快。
  3. 特殊的数据结构:缓存的数据结构通常为 key-value 形式的,也就是说缓存可以做到任何数据量级下的查询数据复杂度为 O(1),所以它的查询效率是非常高的;而数据库采用的是传统数据结构设计,可能需要查询二叉树、或全文搜索、或回表查询等操作,所以其查询性能是远低于缓存系统的。

    1.2 缓存一致性问题

    虽然缓存可以极大的提高查询性能,但同时也带来的新的问题:数据库和缓存一致性的问题。

具体来说,在一个常见的应用场景中,当更新数据库的操作完成后,需要同步更新缓存,以保证缓存中的数据与数据库中的数据保持一致。然而,由于数据库和缓存是两个不同的组件,它们的数据更新操作是异步的,可能存在以下问题:

  1. 数据延迟:数据库更新和缓存更新之间存在时间延迟,导致缓存中的数据不是最新的。这可能会引起数据的不一致,当其他请求读取数据时,可能会读取到旧的数据。
  2. 更新失败:在尝试更新缓存时,可能出现更新失败的情况。例如,缓存节点暂时不可用,网络故障等。如果更新缓存失败而未进行适当的处理,也会导致数据库和缓存之间的数据不一致。

也就说,因为以上原因,可能会导致 A 用户和 B 用户执行了同一个查询操作,但是得到了完全不同的结果,这就是数据库和缓存的一致性问题。

2.如何解决一致性问题?

解决缓存和数据库一致问题的常见解决方案有以下 4 种:

  1. 先修改数据库,后更新缓存。
  2. 先更新缓存,后修改数据库。
  3. 先修改数据库,后删除缓存。
  4. 先删除缓存,后修改数据库。

然而,前 3 种解决方案,有同一个问题,也就是当第一步操作执行完之后,第二步未执行的情况下,就会导致数据库和缓存的一致性问题,例如第一步执行完之后,系统掉电了,那么一致性问题就会一直存在。

相比之下,第 4 种解决方案(先删除缓存,后修改数据库)相比于前三种解决方案更有优势,起码它保证了双方都未执行成功,那么从数据一致性层面来讲,第 4 种方案起码保证了一定的数据一致性,然而第 4 种执行方案依然存在其他问题,例如以下这几个:

  1. 业务完整性问题:程序只执行了一半,第一步执行完了但第二步未执行的情况。
  2. 并发保存旧值的问题:在并发环境下,第四种方案可能会导致缓存保存旧值的情况,例如以下执行情况:虾皮一面:如何保证数据双写一致?

    3.最终解决方案

    所以,想要最大程度的双写一致性问题的最终解决方案是:消息队列 + 延迟双删策略

3.1 为什么要使用消息队列?

因为消息队列里面有消息确认机制,它可以保证我们执行完第一步之后,即时掉电重启的情况,依然可以执行后续的流程,因为之前的消息,未进行消息确认,所以程序重启之后,会继续执行后续的流程,这样就保证了业务执行的完整性。

3.2 什么是延迟双删?

延迟双删指的是删除两次缓存(并且最后一次是延迟删除),具体执行流程如下:

  1. 删除缓存
  2. 更新数据库
  3. 延迟一会再删除缓存

最后一次延迟删除缓存的原因是,为了避免上面因为并发问题导致保存旧值的情况发生,所以会延迟一段时间之后再进行删除操作。这样即使有并发问题,也能最大限度的解决保存旧值的情况,因为是延迟之后删除的,所以即使因为并发问题保存了旧值,但延迟一段时间之后旧值就会被删除,那么这样就自然而然的保证了数据库和缓存的最终一致性。

小结

数据库和缓存双写一致性问题是一道经典的面试题,最初解决方案是先更新数据库、再删除缓存,然而如果发生掉电情况,只执行了前一步操作,那么缓存和数据库就出现了不一致性的问题。为了解决这个问题,所以通常会采用延迟双删 + 消息队列来保证业务的完整执行和数据一致性问题。

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。
点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
4轮onsite都是设计题,Google的面试太狠了...
近年来,大厂尤其Google对于求职者系统设计能力要求越来越高,相应的面试题出现频率也逐年上升。尤其是有工作经验的人跳槽,100%必考。但是,我们大家都知道系统设计很难,如果在面试之前加急准备根本来不及。这个时候,有两个选择:1.放弃系统设计的准备,靠算法、项目和行为面试之类的撑起面试全程;2.其他方面还是照常准备,留出一点时间突击一些系
Wesley13 Wesley13
3年前
2021最新拼多多面经总结!
一直忍着准备放个大招,没想到还是被刷了...前阵子,在准备拼多多的面试,好不容易挺近了三面,没想到被一波完虐,最终面试官请我回家等候通知了。在等候面试过程中,跟周围的程序员同僚聊了起来,顺便加了一手联系方式。嘿嘿,虽然没有过面试,但是东拼西凑,加上自己记下的面试题,把面试内容基本都统计了下来。!拼多多电商部java岗三面落选,记下的面试题,
Wesley13 Wesley13
3年前
Java面试集锦
各位学习Java的同学看过来了,以下是CSDN作者「ThinkWon」总结的面试题。希望对在准备跳槽或者找工作的同学有点帮助。这一波面试题总体来说基本上能够回答面试官的70%问题。虽然有些小节不够完善的,只能靠你自己多面试多总结了。序号内容链接地址1Java基础知识面试题(2020最新版)https://thinkwon.bl
Stella981 Stella981
3年前
63道java面试真题击破BAT招聘套路!跳槽季助你一臂之力
“金三银四”跳槽季,网上出现了各种面试真题,一时会让人眼花缭乱,分不清最该看哪个,小编耗时一星期为大家做了一些java面试的真题。请准备好你的小本本!(https://oscimg.oschina.net/oscnet/e028742d50d457dbf9e0bc1f0f8ef84bab0.jpg)✍面向对象和面向过程的区别·面向过程
Wesley13 Wesley13
3年前
Java面试高频题精选300道题,一份通往阿里的必备指南pdf
就目前大环境来看,跳槽成功的难度比往年高很多。一个明显的感受:今年的面试,无论一面还是二面,都很考验Java程序员的技术功底。最近我整理了一份复习用的面试题及面试高频的考点题及技术点梳理成一份“Java工程师高频面试体系.pdf和一份网上搜集的“Java核心知识点体系文档.pdf”(实际上比预期多花了不少精力),包含集合,JVM,并发编程、Sprin
Stella981 Stella981
3年前
Git神作!2021年Java春招高级面试指南,吃透至少P7
马上到今年的金三银四了,又是跳槽的好季节,准备跳槽的同学都摩拳擦掌准备大面好几场,今天为大家准备了互联网面试必备的1到5年Java面试者都需要掌握的面试题,分别JVM,并发编程,MySQL,Tomcat,网络与IO及Spring系列等等,可以说掌握这些薪资涨10K还是可以的!今天分享给大家的都是目前主流企业使用最高频的面试题库,也都是Java
Stella981 Stella981
3年前
2021年如何面试大厂?回顾今年字节,美团,华为,蚂蚁等Java岗面试经历!文末直接分享笔记
还有20天就是2021年了,回顾一下2010年自己面试过的大厂,这里我说下我的感受今年跳槽成功的难度比往年高了很多,很明显的感受就是:对于今年的java开发朋友跳槽面试,无论一面还是二面,都开始考验一个Java程序员的技术功底和基础。对源码解读和核心原理理解也是成了加分项,特别是对Java的一些核心基础知识点掌握的不够或者没有体系方向的朋友面试也
可莉 可莉
3年前
2021年如何面试大厂?回顾今年字节,美团,华为,蚂蚁等Java岗面试经历!文末直接分享笔记
还有20天就是2021年了,回顾一下2010年自己面试过的大厂,这里我说下我的感受今年跳槽成功的难度比往年高了很多,很明显的感受就是:对于今年的java开发朋友跳槽面试,无论一面还是二面,都开始考验一个Java程序员的技术功底和基础。对源码解读和核心原理理解也是成了加分项,特别是对Java的一些核心基础知识点掌握的不够或者没有体系方向的朋友面试也
可莉 可莉
3年前
2020年末面试总结,史上最全名企Java程序员高频面试知识点解析笔记
就目前大环境来看,跳槽成功的难度比往年高很多。总结一下2020面试的感受:无论一面还是二面,都很考验Java程序员的技术功底!!最近我整理了一份复习用的面试题及面试高频的考点题及技术点梳理成一份“Java程序员高频面试解析及知识点体系笔记.pdf(实际上比预期多花了不少精力),包含集合,JVM,并发编程、Spring,MyBatis,微服务,Redi
Stella981 Stella981
3年前
2020年末面试总结,史上最全名企Java程序员高频面试知识点解析笔记
就目前大环境来看,跳槽成功的难度比往年高很多。总结一下2020面试的感受:无论一面还是二面,都很考验Java程序员的技术功底!!最近我整理了一份复习用的面试题及面试高频的考点题及技术点梳理成一份“Java程序员高频面试解析及知识点体系笔记.pdf(实际上比预期多花了不少精力),包含集合,JVM,并发编程、Spring,MyBatis,微服务,Redi
Wesley13 Wesley13
3年前
Java面试通关宝典(一)
前言年后是跳槽的高峰期,相信有不少朋友已经跃跃欲试了。想要找到好工作,离不开充分的面试准备。刚好沉思君最近在网上看到一份Java面试知识点,觉得很不错,所以摘录了其中比较典型的面试题并给出我的参考答案,供大家参考,如果有不同意见,可以在下方留言,我看到了会一一回复。废话不多说了,接下来我们就直奔主题。面试题精选1.HTTP请求的GET方法