小伙子你好,看你简历上写到了MySQL和Redis。今天咱们就围绕他们两个展开吧。Redis和MySQL是后端开发中举重若轻的重要角色。实际开发中两者也基本上形影不离,为了提升性能和响应,Redis经常存放热点数据,MySQL存放全部数据,保证数据持久化。因此Redis能够说是MySQL的一部分数据。面试
面试官您好,咱们在开发中采起的方案是:先更新数据库,而后删除相应缓存,直到下次请求缓存发现没有数据,再从MySQL中读取,同时将数据更新到Redis。数据库
以下图所示,若是采起更新缓存的方式,可能出现请求A先于请求B发生,更新缓存应该比请求B更新缓存早才对,可是由于网络等缘由,B却比A更早更新了缓存,这就致使了脏数据。
其次,若是你是一个写数据库场景比较多,而读数据场景比较少的业务需求,采用更新缓存的方案就会致使数据压根还没被读取过,但缓存已被频繁的更新,浪费性能。后端
以下图所示,请求A进行写操做,删除缓存,请求B查询发现缓存不存在,就去数据库查询获得旧值,以后将旧值写入缓存,此时请求A再将新值写入数据库。
这种状况就会致使数据不一致的情形出现。并且,若是不采用给缓存设置过时时间策略,该缓存数据永远都是脏数据。缓存
答案是不必定,也可能会出现并发问题。以下图所示,
当步骤Step3的更新数据库操做比步骤Step2的读取数据库操做耗时更短,就有可能使得步骤Step4先于步骤Step5,此时缓存中的就是脏数据。但通常状况下数据库的读操做的速度是远快于写操做的(此点从MySQL的并发读写量就可看出,相同硬件配置下并发读的效率是并发写的数倍)。网络
所以,若是你想实现基础的缓存和数据库双写一致的逻辑,那么在大多数状况下,在不想作过多设计、增长太大工做量的状况下,请
先更新数据库,再删除缓存!
若是MySQL采用了读写分离架构,当请求A更新数据在master库上并删除了缓存,但此时数据库主从同步还未完成。请求B查询缓存发生Cache miss以后从slave库上读取到的仍是旧值,此时也会形成数据不一致。
架构
采用延时双删。以下图所示,请求A更新数据库以后,为防止删除缓存先行发生于请求B的将缓存写入旧值,能够经过将请求A更新完数据库以后休眠一会(例如100ms,200ms,根据实际业务场景拟定),再删除缓存,这样基本能保证缓存中存放的不会是脏数据。主从架构也是这个原理,就是请求A在更新master以后不用当即删除缓存,经过延时双删保证主从同步已经完成,最后删除缓存数据。并发
这里比较优雅的方案是经过异步实现。即开启一个线程池,在请求A的时候开启一个单独的线程,异步的休眠一段时间而后执行缓存删除。固然也能够经过将缓存中相应的key扔到消息队列,经过MQ异步删除,但仅为了异步删除缓存就多加了一层消息队列,可能会形成系统设计更加复杂,而且会带来别的问题。异步
再加一个重试机制,保证删除缓存成功。分布式
没有办法作到绝对的一致性,这是由CAP理论决定的,缓存系统适用的场景就是非强一致性的场景,因此它属于CAP中的AP。性能
CAP理论是分布式系统中的经典理论,即一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。
根据BASE(Basically Available,Soft State和Eventually Consistent)理论,缓存和数据库只能作到数据的最终一致性。
时间也不早了,今天就到这里吧,看出来小伙子对这块掌握的比较深刻。咱们公司就缺乏你这种人才,要不如今就签把Offer签了吧。
这个时候你确定欲绝还迎,一手接Offer一边摆摆手:不行不行,深圳马那边也急着等我给回复呢,催了我好几天了。
面试官一听,payroll组何在,加价!
使用缓存并非一个很简单的事情,尤为在须要缓存与数据库保持强一致的场景,才知道让数据库数据和缓存数据保持一致性是一门很高深的学问。从远古的硬件缓存,操做系统缓存开始,缓存就是一门独特的学问。这个问题也被业界探讨了很是久,争论至今也无果,由于其实这是一个权衡的问题。我是少侠露飞,爱技术,爱分享。