系统设计:缓存

上文提到的负载平衡有助于在数量不断增加的服务器上横向扩展,但缓存将使您能够更好地利用现有资源,并使其他无法实现的产品需求变得可行。缓存利用了引用的局部性原则:最近请求的数据可能会再次被请求。它们几乎应用于计算的每一层:硬件、操作系统、web浏览器、web应用程序等等。缓存就像短期内存:它的空间有限,但通常比原始数据源快,并且包含最近访问的项。

缓存可以存在于体系结构中的所有级别,但通常位于最靠近前端的级别,在那里实现缓存可以快速返回数据,而不会对下游级别造成负担。

应用服务器缓存

将缓存直接放置在请求层节点上可以实现响应数据的本地存储。每次向服务发出请求时,节点都会快速返回本地缓存数据(如果存在)。如果不在缓存中,请求节点将从磁盘查询数据。一个请求层节点上的缓存也可以位于内存(非常快)和节点的本地磁盘上(比进入网络存储更快)。

如果将其扩展到多个节点,会发生什么情况?如果请求层扩展到多个节点,那么每个节点仍然有可能拥有自己的缓存。但是,如果负载平衡器在节点间随机分配请求,则相同的请求将转到不同的节点,从而增加缓存未命中。克服这一障碍的两个选择是全局缓存和分布式缓存。

内容分发网络( Content Distribution Network ->CDN)

CDN是一种缓存,用于为大量静态媒体提供服务的站点。在典型的CDN设置中,请求将首先向CDN请求一块静态介质;CDN将提供该内容,如果它在本地可用的话。如果不可用,CDN将在后端服务器上查询该文件,在本地缓存该文件,并将其提供给请求用户。

如果我们正在构建的系统还不足以拥有自己的CDN,那么我们可以通过在单独的服务器上为静态媒体提供服务来简化将来的转换

子域(例如static.yourservice.com)使用轻量级HTTP服务器,比如Nginx,然后将DNS从服务器切换到CDN。

缓存失效

虽然缓存非常棒,但它确实需要一些维护,以保持缓存与真实来源(例如数据库)保持一致。如果数据库中修改了数据,则在缓存中应失效;如果没有,这可能导致应用程序行为不一致。

解决这个问题称为缓存失效;主要采用三种方案:

Write-through cache (直写缓存/透写)

在这种方案下,数据同时写入缓存和相应的数据库。缓存的数据允许快速检索,而且,由于相同的数据被写入永久存储器,我们将在缓存和存储器之间拥有完全的数据一致性。此外,此方案还确保在发生崩溃、电源故障或其他系统中断时不会丢失任何东西。

尽管直写可以最大限度地降低数据丢失的风险,但是由于每次写操作都必须执行两次才能将成功返回给客户端,因此这种方案的缺点是写操作的延迟更高。

Write-around cache (绕写缓存)

这种技术类似于直写缓存(Write-through cache ),但数据直接写入永久存储器,绕过缓存。这可以减少缓存被随后不会被重新读取的写入操作淹没,但其缺点是,对最近写入的数据的读取请求将创建“缓存未命中”,并且必须从较慢的后端存储中读取,并经历更高的延迟。

Write-back cache (回写缓存)

在这种方案下,数据单独写入缓存,完成后立即向客户端确认。写信给永久储存是在规定的时间间隔或特定条件下进行的。对于写密集型应用程序,这会导致低延迟和高吞吐量,但是,在发生崩溃或其他不利事件时,这种速度会带来数据丢失的风险,因为写数据的唯一副本在缓存中。

cache-aside(旁路缓存)

发生在应用层,应用层保证缓存结果同DB的数据一致性,应用层来负责写入到数据库和整理缓存,缓存层则不必插手此事。

read-through

读取数据时,先尝试从缓存中取得,如果缓存中没有,那么再从数据库中读取,而后也将数据放入缓存中,以便下次读取。这个也是普遍使用的方案。因此也会带来缓存穿透、缓存雪崩、缓存击穿、缓存数据不一致等问题

refresh-ahead

简单的说就是在缓存数据过期前,能自动的刷新缓存数据。举个例子来说,某条数据在缓存中,过期时间是60秒。我们给他设置一个参数,比如是0.8,60x0.8=48秒,那么在前48秒访问该数据,就照正常的取法,直接返回缓存中的数据。当在48-60秒这个区间取数据时,缓存先将之前缓存的结果返回给外部应用程序,然后异步的再从数据库去更新缓存中的值,以尽可能的保证缓存的值是最新的。如果取数据的的时候超过了60秒,就安照read-through的方式。
Refresh-ahead是对未来数据的访问情形的估算,这一个在分布式锁,锁续期中有预估延长缓存时间的实践。

缓存淘汰策略

以下是一些最常见的缓存逐出策略:

1.先进先出(FIFO):缓存逐出首先访问的第一个块不考虑以前访问它的频率或次数。

2.后进先出(LIFO):缓存逐出最近首先访问的块,而不考虑以前访问的频率或次数。

3.最近最少使用(LRU):首先丢弃最近最少使用的项目。

4.最近使用(MRU):与LRU不同的是,首先丢弃最近使用的物品。

5.最少使用频率(LFU):统计需要某个项目的频率。最不常用的会先被丢弃。

6.随机替换(RR):随机选择一个候选项,并在必要时丢弃它以腾出空间。

参考资料

https://lethain.com/introduction-to-architecting-systems-for-scale/

https://en.wikipedia.org/wiki/Cache_(computing)

https://www.cnblogs.com/asis/p/cache-pattern.html

本站文章资源均来源自网络,除非特别声明,否则均不代表站方观点,并仅供查阅,不作为任何参考依据!
如有侵权请及时跟我们联系,本站将及时删除!
如遇版权问题,请查看 本站版权声明
THE END
分享
二维码
海报
系统设计:缓存
上文提到的负载平衡有助于在数量不断增加的服务器上横向扩展,但缓存将使您能够更好地利用现有资源,并使其他无法实现的产品需求变得可行。缓存利用了引用的局部性原则:最...
<<上一篇
下一篇>>