系统性能提升利刃 | 缓存技术使用的实践与思考 (2)

对于上述缺点中,网络耗时等开销是难免的,而且这些操作耗费的时间在可接受范围内,而对于中间件的稳定性则可以通过服务降级、限流或者多级缓存思路来保证。我们主要看中的是它的优点,既然分布式缓存天然能保证缓存一致性,那么我们倾向于将需要频繁访问却又经常变化的数据存放于此。

选择缓存框架的衡量标准

在了解了何时使用缓存以及缓存的优缺点后,我们就准备大刀阔斧开始升级系统了,可紧接着的问题也随之出现,对于本地缓存和分布式缓存,到底应该使用什么框架才是最适用的呢?

现在的技术百花齐放,不同的技术解决的问题侧重点也不同,对于本地缓存来说,如果无资源竞争的代码逻辑,可以使用HashMap,而对于有资源竞争的多线程程序来说,则可以使用ConcurrentHashMap。但以上二者有个通病就是缓存占用只增不减,没有缓存过期机制、也没有缓存淘汰机制。

那么本地缓存是否有更高性能的框架呢?而对于分布式缓存,领域内常用的Redis和Memcache又应该怎样取舍呢?本小节期望通过横向对比的方式,分别给出一个比较通用的缓存框架方案,当然如果有个性化需求的,也可以根据不同缓存框架的特性来取舍。

不同本地缓存框架的横向对比,如下表所示:

 

系统性能提升利刃 | 缓存技术使用的实践与思考

 

 

总结:如果不需要淘汰算法则选择ConcurrentHashMap,如果需要淘汰算法和一些丰富的API,推荐选择Caffeine。

不同分布式缓存框架的横向对比,如下表所示:

 

系统性能提升利刃 | 缓存技术使用的实践与思考

 


 

对于存储容量而言,Memcache采用预先分配不同固定大小存储单元的方式,内存空间使用并不紧凑。如果存储Value对象大小最大为1MB,那么当一个对象有1000KB,那么会存储到大小最匹配1MB的单元中,因此会浪费24KB的内存;而Redis是使用之前才去申请空间,内存使用紧凑,但频繁对内存的扩容和收缩,可能造成内存碎片。

总结:由于Redis具有丰富的数据结构能满足不同的业务场景需求,同时Redis支持持久化,能有效地解决缓存中间件重启后的数据预加载问题,因此大多数应用场景中还是推荐使用Redis。

缓存框架使用过程的知识点

不论是本地缓存还是分布式缓存,在使用缓存提升性能的时候,必然会考虑缓存命中率的高低,考虑缓存数据的更新和删除策略,考虑数据一致性如何维护,本小节主要针对以上的问题来分析不同实现方案的优缺点。

缓存命中率

缓存命中率不仅是系统性能的一个侧面指标,也是优化缓存使用方案的一个重要依据。缓存命中率=请求命中数/请求总数。接下来的若干缓存使用策略所围绕的核心考量点就是在保证系统稳定性的同时,旨在提升缓存命中率。

缓存更新策略

主动请求DB数据,更新缓存

通过在集群中的每台机器都部署一套定时任务,每隔一段时间就主动向数据库DB请求最新数据,然后更新缓存。这样做的好处是可以避免缓存击穿的风险,在缓存失效前就主动请求加载DB数据,完成缓存数据更新的无缝连接。

但这样做也增加了机器的CPU和内存的占用率,因为即使有若干Key的缓存始终不被访问,可还是会被主动加载加载到内存中。也就是说,提高了业务抗风险能力,但对CPU和内存资源并不友好。

详情可参见下图,分布式缓存中存储着DB中的数据,每隔4.9s就会有定时任务执行去更新缓存,而缓存数据失效时间为5s,从而保证缓存中的数据永远存在,避免缓存击穿的风险。但对于Web请求来说,只会访问k1的缓存数据,也即对于k2和k3数据来说,是无效缓存。

 

系统性能提升利刃 | 缓存技术使用的实践与思考

 


 

被动请求DB数据,更新缓存

当有请求到达且发现缓存没数据时,就向DB请求最新数据并更新缓存。这种方案完全可以看做是方案一的互斥方案,它解决的是机器CPU和内存浪费的问题,内存中存储的数据始终是有用的,但却无法避免缓存失效的瞬间又突然流量峰值带来的缓存击穿问题,在业务上会有一定的风险。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzpdz.html