前言

在DEM的某需求中涉及缓存模式的设计,终于要用到我少得可怜的数据库知识了,顺便做个总结

想要提高系统的性能,缓存是最直接最简单的方法之一;缓存一方面可以减少数据库负载,另一方面还可以减少相应时间、节省成本

总的来说,缓存的常见设计模式可分成五种

几个需要了解的词

  • 缓存:广义上的缓存,不仅仅指 Redis 这些常用作缓存的工具
  • 命中缓存:指查询操作中直接在缓存中得到结果
  • 数据更新:指同步缓存与数据库中的数据

Cache-Aside

Cache-Aside 是使用最为广泛的一种模式。应用直接去缓存中找数据,命中缓存则直接返回,如果未命中缓存,则需要先去数据库中查询数据,并将查询到的数据存储到缓存中,示意图如下:

但因为在这种模式下,只有当未命中缓存时,才会从数据库查询最新的数据,所以这样的方式会导致缓存中的数据与数据库中的数据不一致。一般我们会给缓存中的数据设置过期时间(TTL),数据过期后就会去数据库取最新的数据

Cache-Aside模式对缓存失效具有一定的容忍性,即使缓存集群挂掉,我们仍然可以通过直接访问数据库的方式来进行操作;另外值得一提的一点是:缓存中的数据模型可以与数据库中的数据模型不同

Read-Through Cache

Read-Through 的模式与 Cache-Aside 的模式很接近,区别在于,Cache-Aside 是通过应用程序来更新缓存中的数据,而 Read-Through 则是直接通过缓存自身来更新数据,也就是说应用和数据库之间不直接进行连接,并且,由于缓存与数据库之间没有应用程序的介入,read-through cache 中缓存的数据模型不能与数据库中的数据模型不同

Read-through 模式适合读量较大的工作负载,劣势是,当第一次请求数据时,它总是导致缓存丢失,并造成额外的数据加载到缓存的成本

这种模式也存在缓存中数据与数据库中数据不一致的情况,但是相比于给缓存设置过期时间,它只需要和下面的 Write-Through 搭配使用就可以解决这个问题

Write-Through Cache

上面是两种以读为主的缓存,而 Write-Through 模式中,会先将数据写入到缓存中,然后由缓存将数据存入到数据库中

就其本身而言,Write-through 模式似乎没有多大作用,况且它还造成了额外的写延迟成本,因为数据先写到缓存,然后写到数据库,但是 Write-Through 与 Read-Through 相结合可以很好的解决缓存和数据库中数据不一致的问题,Write-Through 每次都会先更新缓存中的数据,这样就可以保证缓存中的数据总是最新的

Write-Around

另一种非常简单的写模式,相比于 Write-Through ,Write-Around 模式中会直接将数据写入数据库中

Cache-Aside 要配合 Write-Around 而不能和 Write-Through 一起使用,因为 Write-Through 模式下会先更新缓存,而这时如果有一个线程未命中缓存,从数据库中读取了旧数据覆盖了缓存中的新数据,就会造成数据错误;而使用 Write-Around 就不会有这个问题

Write-Back

Write-Back 模式可以说是 Write-Through 模式的改良版,Write-Through 模式中,每写一次缓存,缓存就会写一次数据库,而 Write-Back 模式中则是写多次缓存后才会写一次数据库,减少了写延迟,同时也大大减轻服务器的压力

当与read-through相结合的时候,它对于混合工作负载非常有效,最近更新和访问的数据总是在缓存中可用;而同时采用cache-aside和write-back两种策略时,则可以更好地吸收峰值负载期间的峰值

当然, Write-Back 也不是没有缺点,如果缓存出现了问题集体挂掉了,那么缓存中这部分没有持久化的数据就会丢失