前言

volatile是Java程序员必备的基础,也是面试官非常喜欢问的一个话题,本文跟大家一起开启vlatile学习之旅,如果有不正确的地方,也麻烦大家指出哈,一起相互学习~

  • 1.volatile的用法
  • 2.vlatile变量的作用
  • 3.现代计算机的内存模型(计算机模型,总线,MESI协议,嗅探技术)
  • 4.Java内存模型(JMM)
  • 5.并发编程的3个特性(原子性、可见性、有序性、happen-before、as-if-serial、指令重排)
  • 6.volatile的底层原理(如何保证可见性,如何保证指令重排,内存屏障)
  • 7.volatile的典型场景(状态标志,DCL单例模式)
  • 8.volatile常见面试题&&答案解析

如何保证缓存和数据库一致性

说了这么多缓存的必要性,那么使用缓存是不是就是一个很简单的事情了呢,我之前也一直是这么觉得的,直到遇到了需要缓存与数据库保持强一致的场景,才知道让数据库数据和缓存数据保持一致性是一门很高深的学问。

从远古的硬件缓存,操作系统缓存开始,缓存就是一门独特的学问。这个问题也被业界探讨了非常久,争论至今。我翻阅了很多资料,发现其实这是一个权衡的问题。值得好好讲讲。

以下的讨论会引入几方观点,我会跟着观点来写代码验证所提到的问题。

不更新缓存,而是删除缓存

大部分观点认为,做缓存不应该是去更新缓存,而是应该删除缓存,然后由下个请求去去缓存,发现不存在后再读取数据库,写入缓存。

观点引用:《分布式之数据库和缓存双写一致性方案解析》孤独烟

原因一:线程安全角度

同时有请求A和请求B进行更新操作,那么会出现

(1)线程A更新了数据库

(2)线程B更新了数据库

(3)线程B更新了缓存

(4)线程A更新了缓存

这就出现请求A更新缓存应该比请求B更新缓存早才对,但是因为网络等原因,B却比A更早更新了缓存。这就导致了脏数据,因此不考虑。

原因二:业务场景角度

有如下两点:

(1)如果你是一个写数据库场景比较多,而读数据场景比较少的业务需求,采用这种方案就会导致,数据压根还没读到,缓存就被频繁的更新,浪费性能。

(2)如果你写入数据库的值,并不是直接写入缓存的,而是要经过一系列复杂的计算再写入缓存。那么,每次写入数据库后,都再次计算写入缓存的值,无疑是浪费性能的。显然,删除缓存更为适合。

其实如果业务非常简单,只是去数据库拿一个值,写入缓存,那么更新缓存也是可以的。但是,淘汰缓存操作简单,并且带来的副作用只是增加了一次cache miss,建议作为通用的处理方式。

先操作缓存,还是先操作数据库

那么问题就来了,我们是先删除缓存,然后再更新数据库,还是先更新数据库,再删缓存呢?

先来看看大佬们怎么说。

《【58沈剑架构系列】缓存架构设计细节二三事》58沈剑:

对于一个不能保证事务性的操作,一定涉及“哪个任务先做,哪个任务后做”的问题,解决这个问题的方向是:如果出现不一致,谁先做对业务的影响较小,就谁先执行。

假设先淘汰缓存,再写数据库:第一步淘汰缓存成功,第二步写数据库失败,则只会引发一次Cache miss。

假设先写数据库,再淘汰缓存:第一步写数据库操作成功,第二步淘汰缓存失败,则会出现DB中是新数据,Cache中是旧数据,数据不一致。

沈剑老师说的没有问题,不过没完全考虑好并发请求时的数据脏读问题,让我们再来看看孤独烟老师《分布式之数据库和缓存双写一致性方案解析》:

先删缓存,再更新数据库

该方案会导致请求数据不一致

同时有一个请求A进行更新操作,另一个请求B进行查询操作。那么会出现如下情形:

(1)请求A进行写操作,删除缓存

(2)请求B查询发现缓存不存在

(3)请求B去数据库查询得到旧值

(4)请求B将旧值写入缓存

(5)请求A将新值写入数据库

上述情况就会导致不一致的情形出现。而且,如果不采用给缓存设置过期时间策略,该数据永远都是脏数据。

所以先删缓存,再更新数据库并不是一劳永逸的解决方案,再看看先更新数据库,再删缓存这种方案怎么样?

先更新数据库,再删缓存这种情况不存在并发问题么?

不是的。假设这会有两个请求,一个请求A做查询操作,一个请求B做更新操作,那么会有如下情形产生

(1)缓存刚好失效

(2)请求A查询数据库,得一个旧值

(3)请求B将新值写入数据库

(4)请求B删除缓存

(5)请求A将查到的旧值写入缓存

ok,如果发生上述情况,确实是会发生脏数据。

然而,发生这种情况的概率又有多少呢?

发生上述情况有一个先天性条件,就是步骤(3)的写数据库操作比步骤(2)的读数据库操作耗时更短,才有可能使得步骤(4)先于步骤(5)。可是,大家想想,数据库的读操作的速度远快于写操作的(不然做读写分离干嘛,做读写分离的意义就是因为读操作比较快,耗资源少),因此步骤(3)耗时比步骤(2)更短,这一情形很难出现。

先更新数据库,再删缓存依然会有问题,不过,问题出现的可能性会因为上面说的原因,变得比较低!

(补充说明:我用了“先更新数据库,再删缓存”且不设过期时间策略,会不会有问题呢?由于先缓存和更新数据库不是原子的,如果更新了数据库,程序歇逼,就没删缓存,由于没有过期策略,就永远脏数据了。)

所以,如果你想实现基础的缓存数据库双写一致的逻辑,那么在大多数情况下,在不想做过多设计,增加太大工作量的情况下,请先更新数据库,再删缓存!

我非要数据库和缓存数据强一致怎么办

那么,如果我非要保证绝对一致性怎么办,先给出结论:

没有办法做到绝对的一致性,这是由CAP理论决定的,缓存系统适用的场景就是非强一致性的场景,所以它属于CAP中的AP。

所以,我们得委曲求全,可以去做到BASE理论中说的最终一致性

最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性

大佬们给出了到达最终一致性的解决思路,主要是针对上面两种双写策略(先删缓存,再更新数据库/先更新数据库,再删缓存)导致的脏数据问题,进行相应的处理,来保证最终一致性。

缓存延时双删

问:先删除缓存,再更新数据库中避免脏数据?

答案:采用延时双删策略。

上文我们提到,在先删除缓存,再更新数据库的情况下,如果不采用给缓存设置过期时间策略,该数据永远都是脏数据。

那么延时双删怎么解决这个问题呢?

(1)先淘汰缓存

(2)再写数据库(这两步和原来一样)

(3)休眠1秒,再次淘汰缓存

这么做,可以将1秒内所造成的缓存脏数据,再次删除。

那么,这个1秒怎么确定的,具体该休眠多久呢?

针对上面的情形,读者应该自行评估自己的项目的读数据业务逻辑的耗时。然后写数据的休眠时间则在读数据业务逻辑的耗时基础上,加几百ms即可。这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。

如果你用了mysql的读写分离架构怎么办?

ok,在这种情况下,造成数据不一致的原因如下,还是两个请求,一个请求A进行更新操作,另一个请求B进行查询操作。

(1)请求A进行写操作,删除缓存

(2)请求A将数据写入数据库了,

(3)请求B查询缓存发现,缓存没有值

(4)请求B去从库查询,这时,还没有完成主从同步,因此查询到的是旧值

(5)请求B将旧值写入缓存

(6)数据库完成主从同步,从库变为新值

上述情形,就是数据不一致的原因。还是使用双删延时策略。只是,睡眠时间修改为在主从同步的延时时间基础上,加几百ms。

采用这种同步淘汰策略,吞吐量降低怎么办?

ok,那就将第二次删除作为异步的。自己起一个线程,异步删除。这样,写的请求就不用沉睡一段时间后了,再返回。这么做,加大吞吐量。

所以在先删除缓存,再更新数据库的情况下,可以使用延时双删的策略,来保证脏数据只会存活一段时间,就会被准确的数据覆盖。

在先更新数据库,再删缓存的情况下,缓存出现脏数据的情况虽然可能性极小,但也会出现。我们依然可以用延时双删策略,在请求A对缓存写入了脏的旧值之后,再次删除缓存。来保证去掉脏缓存。

分享

首先分享一份学习大纲,内容较多,涵盖了互联网行业所有的流行以及核心技术,以截图形式分享:

(亿级流量性能调优实战+一线大厂分布式实战+架构师筑基必备技能+设计思想开源框架解读+性能直线提升架构技术+高效存储让项目性能起飞+分布式扩展到微服务架构…实在是太多了)

其次分享一些技术知识,以截图形式分享一部分:

Tomcat架构解析:

算法训练+高分宝典:

Spring Cloud+Docker微服务实战:

最后分享一波面试资料:

切莫死记硬背,小心面试官直接让你出门右拐

1000道互联网Java面试题:

Java高级架构面试知识整理:

转存中…(img-6cZdRy9f-1650006348372)]

最后分享一波面试资料:

切莫死记硬背,小心面试官直接让你出门右拐

1000道互联网Java面试题:

[外链图片转存中…(img-FGnCmlYQ-1650006348373)]

Java高级架构面试知识整理:

[外链图片转存中…(img-4ZAxY4MP-1650006348373)]

mongodb分片原理,字节跳动算法工程师面试总相关推荐

  1. java大数据分析技术栈,字节跳动算法工程师面试总

    前言 假如你去面试,面试官让你聊一下对索引的理解,然而你对索引的理解仅限于,检索数据就是快,是一种数据结构这个层面,那你就只能回家等通知了. 为了避免这种尴尬的事情发生,咔咔用时两天将索引的内容在自己 ...

  2. MySQL最左匹配原则,道儿上兄弟都得知道的原则,字节跳动算法工程师面试总结

    目录 一.最左匹配原则的原理 二.违背最左原则导致索引失效的情况 三.查询优化器偷偷干了哪些事儿 四.需要你mark的知识点 1.如何通过有序索引排序,避免冗余执行order by 2.like 语句 ...

  3. Java岗大厂面试百日冲刺 - 日积月累,每日三题【Day28,字节跳动算法工程师面试

    车票 面试题1:说一下你对聚集索引与非聚集索引的理解,以及他们的区别? 追问1:为什么聚集索引可以创建在任何一列上,如果此表没有主键约束,即有可能存在重复行数据呢? 追问2:聚集索引一定比非聚集索引性 ...

  4. 熬了整整30天,字节跳动算法工程师面试

    技术能力 通常,「技术能力」这个部分将紧接着你的个人简介之后,放在简历的核心版面.这样设计是有道理的,因为它能够帮助雇主更快的判断你的技能是否与需求相吻合. 因此在制作这一部分内容时,你应该考虑以下两 ...

  5. 字节跳动算法工程师总结:腾讯+字节+阿里面经真题汇总,含面试题+答案

    前言 周末花了2天时间学习了额RabbitMQ,总结了最核心的知识点,带大家快速掌握RabbitMQ,整理不易希望帮忙点赞,转发,分享下,谢谢 一.SpringCloud 1.服务发现 Eureka ...

  6. 字节跳动算法工程师总结:java资料文件

    一面(个人感觉回答得还不错) 1. 自我介绍 2. 说项目,项目问的非常深(本人提到之前做过的一篇关于FULL GC的问题定位和优化的项目以及一个多并发的项目) 2.1 对于自己产于过项目的系统定位是 ...

  7. 字节跳动算法工程师总结:java接口实验报告总结

    本文框架如下 第一部分,主要是在阅读代码过程中的日志和笔记: 第二部分,主要介绍了 Redis 的主要框架,以及 Redis 是如何提供服务的,从一个最简单的命令开始讲起: 第三部分,主要介绍 Red ...

  8. 字节跳动算法工程师总结:java自学路线及推荐书籍

    分享第一份Java基础-中级-高级面试集合 Java基础(对象+线程+字符+接口+变量+异常+方法) Java中级开发(底层+Spring相关+Redis+分布式+设计模式+MySQL+高并发+锁+线 ...

  9. 字节跳动算法工程师总结:java抽象类和接口实验报告

    本文框架如下 第一部分,主要是在阅读代码过程中的日志和笔记: 第二部分,主要介绍了 Redis 的主要框架,以及 Redis 是如何提供服务的,从一个最简单的命令开始讲起: 第三部分,主要介绍 Red ...

最新文章

  1. 自动驾驶 | MINet:嵌入式平台上的实时Lidar点云数据分割算法,速度可达 20-80 FPS!...
  2. 入选CVPR 2022!一举打败16个同类模型,视频超分比赛冠军算法!
  3. python支持的数据类型float_Python基本数据类型之int 、 float
  4. 【Android 安全】DEX 加密 ( 代理 Application 开发 | multiple-dex-core 依赖库开发 | 配置元数据 | 获取 apk 文件并准备相关目录 )
  5. MOSS 2007 EventHandler 开发步骤
  6. 内部错误:无法加载 ABAP 报表 LVBRKF0I
  7. tomcat的备份脚本
  8. java调用sql返回list_Spring JdbcTemplate实现有java.sql.ResultSet结果集返回的存储过程调用 | 学步园...
  9. GATNE:阿里电商场景下的大规模异构网络表示学习 KDD2019
  10. 联姻寺库,一次半斤八两的合作,趣店的奢侈品生意仍看不见未来
  11. HDU 1257 最少拦截系统【最长上升子序列】
  12. android 代码植入,Android Studio之Debug运行期代码植入的方法
  13. 报Failed to resolve: org.jetbrains.kotlin:kotlin-stdlib-jre7的错误
  14. 把人工智能体验做到极致,微软深挖人工情感的商机
  15. 从入门到冠军 中国移动人群画像赛TOP1经验学习研究
  16. 代码托管gitHub中国官网
  17. 刘强东的“毛乌素”之斗
  18. i春秋百度杯CTF比赛2016年12月场writeup
  19. 线性筛——约数的个数
  20. word中英文间距太大了,勾选允许中英文换行后,英文单词被拆开

热门文章

  1. 用数组+链表实现哈希表
  2. 数据库---主键,候选键,超键
  3. winXp 共享打印问题处理方法(终极版)
  4. Android手写签名 附带背景图设置
  5. 禅与摩托车维修艺术_摩托车与编程之禅
  6. 根据IP地址获取地理位置
  7. 计算机取消uefi启动项,如何使用老毛桃winpe删除或添加UEFI BIOS启动项?
  8. When Hybrid Cloud Meets Flash Crowd: Towards Cost-Effective Service Provisioning--INFOCOM 2015
  9. 数据挖掘技术具有哪些特点?
  10. 两岸开源社群面面观(总结篇)