目录
1 缓存策略
2 缓存类型
3 缓存淘汰策略
4 缓存常见问题
5 总结
本文介绍了后台开发中使用的缓存技术,如缓存策略、缓存类型,包括本地缓存和分布式缓存,还有缓存淘汰策略,以及缓存使用中的常见问题,如一致性问题、缓存雪崩、缓存穿透、缓存击穿。
缓存(Cache)是一种存储技术,可以存储数据,以便快速获取数据。缓存最重要的是两个特性:存储、快速获取。缓存的本质:「用空间换时间」,用快速存储的介质保存数据,以提升数据访问的速度。
在计算机的世界里,缓存被广泛应用于硬件(如 CPU 高速缓存、寄存器)和软件中(如浏览器缓存、CDN、应用程序中的缓存等)。
后台中的缓存
后台开发中,缓存的使用场景一般有:
01
缓存策略
缓存策略通常分为两种,通读缓存和旁路缓存。
1.1 通读(read-through)缓存
在使用通读缓存时,应用程序会尝试从缓存中获取数据。如果该数据已存在于缓存中,那么缓存会直接返回该数据。若缓存中并未包含所需数据,那么缓存会自行访问数据源来获取数据,并将获取的数据返回给应用程序,同时将这份数据保存在缓存中。如此一来,当应用程序下次需要同样的数据时,就能够直接从 read-through 缓存中获取,无需再次访问数据源。
通读缓存的应用有很多,比如 CDN:
CDN(Content Delivery Network)即内容分发网络,是一种分布式的网络架构。依赖于服务商提供的广泛分布于各地的 CDN 服务器,通过把数据分发并缓存到各地的 CDN 服务器上,当用户请求数据时,CDN 会匹配离用户距离最近的节点并返回缓存数据,以此来提高用户访问资源的速度。CDN 一般用来加速静态资源的传输,比如图片、CSS、HTML 等内容。而动态的内容,如搜索结果、单据信息等则不合适,这类数据需要应用服务器实时计算后才能返回。
腾讯云 CDN 具有海量资源储备、全球智能调度、一键接入、丰富功能等产品优势,欢迎企业及用户了解试用:
https://cloud.tencent.com/product/cdn
配图来源:seobility
1.2 旁路(cache-aside)缓存
与通读缓存不同,旁路缓存不直接与数据源打交道。应用程序尝试从旁路缓存获取数据,如果数据不存在,则返回空。应用程序自行请求数据源获取数据,并写入旁路缓存。这样下次相同的请求到达时,应用程序从旁路缓存中则会获取到数据。
通读缓存和旁路缓存这两种策略,一般来说都会灵活应用、互相包含。比如通读缓存中,对数据的查询和写缓存,使用的就是旁路缓存策略。而该实现被整体封装起来,对外表现的则是通读缓存策略。
02
缓存类型
在后台服务中,缓存的类型可以分为本地缓存和分布式缓存。
2.1 本地缓存(local cache)
本地缓存,与应用程序的进程有相同的生命周期,存放于应用程序的堆空间(heap)中。
2.2 分布式缓存(remote cache)
分布式缓存,也可理解为远端缓存。使用外部的缓存服务,独立部署,与应用程序解藕。
2.2.1 常见的缓存服务
Redis
Memcache
选择 Redis 还是 Memcached 取决于具体的应用需求。如果需要一个轻量级、专注于缓存的解决方案,且不需要复杂的数据类型和持久化,Memcached 可能是更合适的选择。而如果应用需要利用丰富的数据类型、持久化以及构建高可用的分布式系统,Redis 将是更强大、更灵活的选择。
03
缓存淘汰策略
由于缓存的空间是有限的,如果缓慢的空间被使用完了,则需要淘汰旧的数据,腾出空间给新的数据使用。缓存淘汰常用的几种策略有如下几种。
3.1 FIFO(First In First Out)算法
FIFO 算法是最简单最好理解的,其策略是:先进先出,如果一个数据的写入时间越早,说明将来被访问的几率越低。因此 FIFO 算法优先淘汰最早写入的数据。
3.2 LRU(Least Recently Used)算法
LRU 算法,即最近最少使用算法。如果一个数据最近被访问了,那么将来被访问的几率越高。反之,如果一个数据很久都没有访问,那么将来被访问的几率越低。其淘汰策略就是:优先淘汰最久没有被使用到的数据。LRU 通常使用双向链表+哈希表来实现。
3.3 LFU(Least Frequently Used)算法
LFU 算法,即最少使用算法。如果一个数据被访问的次数越多,那么将来被访问的几率越高。反之,如果一个数据被访问的次数越少,那么将来被访问的几率越小。其淘汰策略就是:优先淘汰最少被使用的数据。LFU 算法可以使用小顶堆+哈希表来实现。
大部分本地缓存的三方库或缓存服务,都支持设置淘汰算法,无需自行实现。
04
缓存常见问题
4.1 缓存与数据源的一致性
缓存的数据是来自数据源的,当数据源被更新了,而缓存没有被更新,后台服务则会从缓存中取到脏数据,这就有数据脏读的问题。对于这个问题,主要的策略有两种。
4.1.1 过期失效
每个写入缓存中的数据,都设置一个合适的过期时间,在有效期内都返回缓存的数据。当缓存数据过期失效,则会回源到数据源,重新缓存最新的数据。这种情况会有数据脏读的问题,不过采用过期失效的数据,一般是更新不频繁的数据,比如用户信息、热门信息等,存在一定的数据延迟是可以接受的。
4.1.2 主动更新
当数据源的数据更新了,程序主动去更新缓存数据,保证缓存中的数据始终是最新的。这种策略,适合对数据的时效性要求很高的数据,比如库存、余额等等。主动更新的代价则是代码的复杂度增加,所有涉及数据更新的操作,都需要更新其缓存数据。
无论是过期失效还是主动更新,首先应该分析当前场景对数据的时效性要求是否很高?如不是,过期失效足矣。如果是,需要衡量主动更新的代价能否接受,比如代码复杂度增加。否则是否可以通过缩短失效时间而采取过期失效策略来折中处理。
4.2 缓存雪崩
缓存雪崩是指在同一时间点后台服务中的缓存大量过期失效,当服务的并发量很高时,大量的数据请求同时到达数据源服务(比如数据库或其他服务),引起数据源服务的瞬时负载增大,甚至崩溃。
引起缓存雪崩的原因一般有两种:
解决办法:
4.3 缓存穿透
缓存穿透是指同一时间大量的空值请求到达后台服务,空值请求是指查询数据源后无数据的请求,由于数据源返回空数据,所以缓存层没有将空值保存,导致空值请求必然会穿透缓存层,透传到数据源。
引起缓存穿透的原因,一般有:
解决办法:
4.4 缓存击穿
缓存击穿是指某个热点数据的缓存失效了,然后同一时间有大量的请求访问该热点数据,由于缓存失效,这些请求同时被透传到数据源服务,导致数据源的负载增加,甚至崩溃。
引起缓存击穿的原因,一般是:热点数据的缓存失效时,高并发请求同时访问该数据。
解决办法:
05
总结
本文详细地介绍了后台开发中的缓存技术,希望能对你的日常工作有所帮助和启发。熟练掌握各种缓存策略和机制,解决缓存问题,对于程序员而言至关重要,可以在很大程度上提升后台开发的效率、稳定性和用户体验。