缓存模式

系列 - 缓存技术系列
警告
本文最后更新于 2023-07-08,文中内容可能已过时。

最常见的缓存模式,读取数据时先查找缓存,如果缓存中不存在,那么从数据库中获取数据,然后将数据放入缓存。

https://image.linux88.com/2023/07/08/df103de96ad1d78d779a2073c861a41a.svg

  • 优点:简单,易于理解和实现,能保持数据在数据库和缓存中的一致性。
  • 缺点:需要应用代码维护缓存的一致性,增加了应用的复杂性。
  • 适用场景:适用于读多写少且数据一致性要求不高的场景。
  • 案例:用户信息查询,如查询用户的购物车信息,先查询缓存,没有则查询数据库,然后将数据库数据写入缓存。

在此模式下,缓存负责向数据库读取数据。当缓存未命中时,它将自动从数据库加载数据,然后将数据添加到缓存。 https://image.linux88.com/2023/07/08/a9064f10e3f36e81a0cc6bafd3320202.svg

  • 优点:减少了客户端的复杂性,将缓存操作封装在缓存层,简化了客户端代码。
  • 缺点:可能会增加单次请求的延时。
  • 适用场景:读操作远多于写操作,数据更新频率不高的情况。
  • 案例:商品详情页信息展示,信息变化不频繁,读取频繁。

这种模式可以预先加载将要过期的数据,避免在客户请求时出现缓存未命中的情况。 https://image.linux88.com/2023/07/08/5a08b495b56ef055b749a897b506cfc4.svg

  • 优点:提高了读操作的性能,避免了缓存雪崩的风险。

  • 缺点:预测算法可能存在误判,浪费系统资源。

  • 适用场景:读操作较多,数据访问模式较稳定,可以预测的场景。

  • 案例:热门新闻列表,新闻的热度可以预测,可以提前将可能热门的新闻加载到缓存中。

此模式下,写入数据时,同时写入缓存和数据库。这确保了任何时候缓存都包含了最新的数据。

https://image.linux88.com/2023/07/08/44af5f3736e7b193dd75a979ee6d0305.svg

  • 优点:数据一致性好,降低了数据丢失的风险。
  • 缺点:每次写操作都需要同时写入缓存和数据库,可能影响性能。为了解决这个问题,一些系统可能会使用异步写入数据库的方法,或者使用其他缓存模式,如 Write-Behind 模式。
  • 适用场景:对数据一致性有较高要求的场景。
  • 案例:银行账户余额更新,需要实时将数据更新到数据库和缓存中,确保数据一致性。

在此模式下,写操作首先写入缓存,并且定期异步地将数据写入数据库,这可以降低数据库的写入压力。

https://image.linux88.com/2023/07/08/848da9a8d5f92fbd13f5b067afe68249.svg

  • 优点:提高了写操作的性能,可以合并写操作,减轻了数据库的负载。
  • 缺点:数据一致性较差,有数据丢失的风险。
  • 适用场景:写操作较多,对数据一致性要求不特别高的场景。
  • 案例:用户行为日志记录,用户的每一次点击、浏览都要记录,但对数据一致性要求不高。

当数据被写入时,直接写入数据库,而不是写入缓存。这种模式可以防止大量的写入操作导致缓存中的其他数据被淘汰。

https://image.linux88.com/2023/07/08/368020267bdeaaa79047b5d019a5855d.svg

  • 优点
    • 缓存不会被一次性或者不常使用的数据填充,保护了缓存中频繁使用的数据不被替换出去。
    • 对于只写入一次而不再读取的数据,这种模式可以减少缓存的 I/O 操作。
  • 缺点:如果一个新写入的数据在短时间内需要被读取,那么这个读取操作就会导致缓存未命中,这就需要再次从存储设备中加载数据,增加了数据访问的延迟。
  • 适用场景:当预期在写入数据后立即重新读取的可能性较低,或者写操作比读操作更频繁的系统中,Write-Around 缓存策略是一个非常好的选择。例如在日志记录系统中,数据主要是被写入,而不需要被频繁地读取,这种场景下使用 Write-Around 策略是合适的。
  • 案例: 一个典型的案例就是操作系统或数据库管理系统中的磁盘缓存管理。在这种情况下,如果有大量的顺序写操作(例如,日志记录),使用 Write-Around 策略可以避免填充缓存空间(直接写入磁盘而不是缓冲),因为这些顺序写入的数据可能在短时间内不会再被读取。

多级缓存策略常被应用在大规模分布式系统中,通过设计多级的缓存策略,优化数据的读取和写入性能。这种策略的主要目标是尽可能地将数据缓存存储在靠近需要它的地方。 https://image.linux88.com/2023/07/08/74d099ac8c07b555dad713f3ecad2707.svg

  • 优点:充分利用了各级缓存的优点,提高了系统的性能。
  • 缺点:复杂性增加,需要维护各级缓存之间的一致性。
  • 适用场景:大规模分布式系统,数据访问热度分布不均的场景。
    • 大规模分布式系统:在大规模分布式系统中,读写压力大、并发用户多,使用多级缓存可以很好地处理这些问题。
    • 数据访问热度分布不均的场景:在这种场景中,一级缓存(例如内存缓存)可以存储访问最频繁的数据,二级缓存(例如本地磁盘)可以存储访问频率较低的数据。
  • 案例
    • 大型电商网站:如淘宝、京东等,他们在系统内部设计多级缓存策略,如 CDN 缓存、内存缓存、数据库缓存等。一级缓存(例如内存缓存)负责存储最常被访问的商品信息,二级缓存(例如本地磁盘或数据库缓存)负责存储访问频率较低的商品信息,这样能更高效地处理大规模用户的访问请求,提供稳定快速的服务。
    • 社交网络:如 Facebook、Twitter 等,他们的新鲜事(Feed)系统通常会采用多级缓存策略,以优化大量用户的信息读取性能。

结果缓存是将一次计算的结果存储在缓存中,当下次需要这个计算结果时,可以直接从缓存中获取,避免了重复的计算过程,从而大大提高了系统性能。

https://image.linux88.com/2023/07/08/7b081af506126f8d33f8dc18812e1a63.svg

  • 优点:将计算结果缓存起来,减轻了服务器的计算压力。
  • 缺点:计算结果的更新和过期需要管理,可能出现缓存和实际数据不一致的情况。
  • 适用场景:计算复杂,但数据更新不频繁的场景。
  • 案例:电商网站的商品推荐列表,计算复杂,但推荐结果不需要实时更新。

在电商网站中,商品详情页的访问量巨大且访问热度各异。

例如,对于热门商品,为了提高性能,我们可以采用 Read-Through 和 Multi-Level Caches 模式。

当用户请求商品详情时,首先从一级缓存(例如内存缓存)查询,如果没有命中,再从二级缓存(例如本地磁盘缓存)查询,如果还没有命中,再从数据库加载数据,并将数据同时写入一级缓存和二级缓存。这样,对于热门商品的访问,大部分情况下可以直接从一级缓存获取数据,大大提高了访问性能。

同时,对于不热门的商品,使用 Write-Behind 模式,先将更新写入缓存,然后异步地更新数据库,以提高写操作的性能。

在社交网络中,新鲜事(Feed)系统需要处理大量的读写操作。

例如,对于新鲜事的读取,可以使用 Read-Through 和 Multi-Level Caches 模式,先从一级缓存查询,如果没有命中,再从二级缓存查询,如果还没有命中,再从数据库加载数据,并将数据同时写入一级缓存和二级缓存。

对于新鲜事的发布,可以使用 Write-Around 模式,先将新鲜事直接写入数据库,然后在一级缓存和二级缓存中分别存储新鲜事的元数据和全量数据。这样,既可以提高读操作的性能,又可以避免因写操作而填充缓存空间。

在数据库系统中,通常会使用多种缓存模式来提高性能。

例如,使用 Read-Through 模式来处理查询操作,当用户查询数据时,先从缓存中查询,如果没有命中,再从磁盘加载数据,并将数据写入缓存。

使用 Write-Through 或 Write-Behind 模式来处理更新操作,当用户更新数据时,先将更新写入缓存,然后同步或异步地更新磁盘。同时,还可以使用 Multi-Level Caches 模式,通过在内存和磁盘之间设置多级缓存,以优化数据的读取和写入性能。

缓存模式是在设计和实施缓存策略时,常用的一些方法和实践。Cache-Aside 模式直接从缓存中获取数据,如果缓存中没有数据,则从数据库中获取并将其放入缓存。Read-Through 模式将数据的加载逻辑封装在缓存中,当缓存未命中时,自动从数据库加载数据并更新缓存。Refresh-Ahead 模式主动地在缓存过期之前更新缓存数据,以避免缓存冷启动的性能问题。Write-Through 模式在写数据时,同时更新缓存和数据库,保持二者的数据一致性。Write-Behind 模式在写数据时先更新缓存,然后异步更新数据库,以提高写操作的性能。Write-Around 模式在写数据时直接写入数据库,避免写操作填充缓存空间。Multi-Level Caches 模式在一个系统中使用多级缓存,以平衡缓存的性能和存储成本。Result Cache 模式是在数据访问层实现缓存,主要用于缓存数据库查询结果,以提高重复查询的性能。各种缓存模式各有优缺点,适用于不同的应用场景和需求。