缓存ABC

缓存ABC

Intro

缓存是一种比较常见的用来将提升系统性能的方式。从线程缓存、进程缓存、到内存缓存再到分布式缓存再到CDN,都是属于缓存的范畴。html

缓存的本质是空间换时间以提升读的效率,牺牲一些内存空间来换取以后的快速读取与访问。git

缓存3问

为何须要缓存?

通常在项目中,最消耗性能的地方就是后端服务了,然后端的数据库的读写频率经常都是不均匀分布的,并且大多状况是读多写少,而且读操做(select)还会有一些复杂的判断条件,好比 like、group、join 等等,这些语法是很是消耗性能的,全部会出现不少的慢查询,所以业务量上来以后,数据库很容易在读操做的环节遇到瓶颈。github

添加了缓存以后,针对绝大多数的读多写少的业务来讲可以很大程度上提升业务的qps、提升系统的反应速度,提高用户的用户体验。数据库

使用缓存会遇到哪些问题呢?

  1. 数据一致性问题

虽然缓存能够提升总体性能,可是它也可能会带来别的问题。例如使用缓存以后,就至关于把数据存放了2份,一份是在数据库中,另外一份存放在缓存中。当有新的数据要写入或者旧数据须要更新的时候,若是咱们只更新了其中一份数据源,那两边的数据就不一致了,这里就涉及到使用缓存的一个原则,若是数据有很强的一致性要求就要慎重考虑是否适合使用缓存了。后端

  1. 缓存过时时间问题缓存

    设计缓存的过时时间必须与业务实际状况相结合。由于若是设计的过时时间过短了,那会致使缓存效果不佳,仍会形成频繁的从数据库中往缓存里写数据。若是缓存设计的过时时间过长又会致使内存空间的浪费。服务器

  2. 缓存的命中率问题多线程

    这也是设计缓存中须要存放哪些数据的很重要一点,若是缓存命中率太低,就会失去缓存效果。通常对于热点数据而言,要保证命中率达到70%以上效果最佳。并发

  3. 缓存的击穿/穿透/雪崩问题异步

  • 缓存击穿

通常的缓存系统,都是按照key去缓存查询,若是不存在对应的value,就应该去后端系统查找(好比db)。若是key对应的value是必定不存在的,而且对该key并发请求量很大,就会对后端系统形成很大的压力。在高并发下,多线程同时查询同一个资源,若是缓存中没有这个资源,那么这些线程都会去数据库查找,对数据库形成极大压力,缓存失去存在的意义

  • 缓存雪崩

当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(好比db)带来很大压力。

  • 缓存穿透

缓存穿透是指用户查询数据,在数据库没有,天然在缓存中也不会有。这样就致使用户查询的时候,在缓存中找不到,每次都要去数据库中查询。

什么样的情景下使用缓存

  • 读多写少的业务场景
  • 对数据一致性性要求不高,容许必定时间内的数据不一致
  • 容许缓存丢失,使用缓存要考虑缓存miss的处理

缓存的更新策略具体有哪些?

典型的缓存模式,通常有以下几种:

  • Cache Aside

  • Read/Write Through

  • Write Behind

每种模式都有不一样的特色,适应与不一样的项目场景,下面来依次看看:

Cache Aside 模式

image

这是你们常常用到的一种策略模式。这种模式主要流程以下:

应用在查询数据的时候,先从缓存Cache中读取数据,若是缓存中没有,则再从数据库中读取数据,获得数据库的数据以后,将这个数据也放到缓存Cache中。

若是应用要更新某个数据,也是先去更新数据库中的数据,更新完成以后,则经过指令让缓存Cache中的数据失效。

这里为何不让更新操做在写完数据库以后,紧接着去把缓存Cache中的数据也修改了呢?

主要是由于这样作的话,就有2个写操做的事件了,担忧在并发的状况下会致使脏数据,举个例子:

假如同时有2个请求,请求A和请求B,并发的执行。请求A是要去读数据,请求B是要去更新数据。初始状态缓存中是没有数据的,当请求A读到数据以后,准备往回写的时候,此刻,请求B正好要更新数据,更新完了数据库以后,又去把缓存更新了,那请求A再往缓存中写的就是旧数据了,属于脏数据。

那么 Cache Aside 模式就没有脏数据问题了吗?不是的,在极端状况下也可能会产生脏数据,好比:

假如同时有2个请求,请求A和请求B,并发的执行。请求A是要去读数据,请求B是要去写数据。假如初始状态缓存中没有这个数据,那请求A发现缓存中没有数据,就会去数据库中读数据,读到了数据准备写回缓存中,就在这个时候,请求B是要去写数据的,请求B在写完数据库的数据以后,又去设置了缓存失效。这个时候,请求A因为在数据库中读到了以前的旧数据,开始往缓存中写数据了,此时写进入的就也是旧数据。那么最终就会致使,缓存中的数据与数据库的数据不一致,形成了脏数据。

不过这种几率比上面一种几率要小不少。因此总体而言  Cache Aside 模式 仍是一种比较简单实用的方式。

Read/Write Through 模式

image

这个模式其实就是将 缓存服务 做为主要的存储,应用的全部读写请求都是直接与缓存服务打交道,而无论最后端的数据库了,数据库的数据由缓存服务来维护和更新。不过缓存中数据变动的时候是同步去更新数据库的,在应用的眼中只有缓存服务。

流程就至关简单了:

应用要读数据和更新数据都直接访问缓存服务,缓存服务同步的将数据更新到数据库

这个模式出现脏数据的几率比较低,可是太依赖缓存服务了,对缓存服务的稳定性有较大要求。

Write Behind 模式

这个模式就是 Read/Write Through 模式 的一个变种。区别就是 Read/Write Through 模式的缓存写数据库的时候是同步的,而 Write Behind 模式 的缓存操做数据库是异步的。

流程以下:

应用要读数据和更新数据都直接访问缓存服务

缓存服务异步的将数据更新到数据库(经过异步任务)

这个模式的特色就是速度很快,效率会很是高,可是数据的一致性比较差,还可能会有数据的丢失状况,实现逻辑也较为复杂。

Reference

Contact

contact me:weihanli@outlook.com

相关文章
相关标签/搜索