前 言
在高并发的分布式的系统中,缓存是必不可少的一部分。没有缓存对系统的加速和阻挡大量的请求直接落到系统的底层,系统是很难撑住高并发的冲击,所以分布式系统中缓存的设计是很重要的一环。下面就来聊聊分布式系统中关于缓存的设计以及过程中遇到的一些问题。
缓存的收益与成本
使用缓存我们得到以下收益:
加速读写。因为缓存通常是全内存的,比如Redis、Memcache。对内存的直接读写会比传统的存储层如MySQL,性能好很多。举个例子:同等配置单机Redis QPS可轻松上万,MySQL则只有几千。加速读写之后,响应时间加快,相比之下系统的用户体验能得到更好的提升。
降低后端的负载。缓存一些复杂计算或者耗时得出的结果可以降低后端系统对CPU、IO、线程这些资源的需求,让系统运行在一个相对资源健康的环境。
但随之以来也有一些成本:
数据不一致性:缓存层与存储层的数据存在着一定时间窗口一致,时间窗口与缓存的过期时间更新策略有关。
代码维护成本:加入缓存后,需要同时处理缓存层和存储层的逻辑,增加了开发者维护代码的成本。
运维成本:引入缓存层,比如Redis。为保证高可用,需要做主从,高并发需要做集群。
综合起来,只要收益大于成本,我们就可以采用缓存。
缓存的更新
缓存的数据一般都是有生命时间的,过了一段时间之后就会失效,再次访问时需要重新加载。缓存的失效是为了保证与数据源真实的数据保证一致性和缓存空间的有效利用性。下面将从使用场景、数据一致性、开发运维维护成本三个方面来介绍几种缓存的更新策略。
1、LRU/LFU/FIFO
这三种算法都是属于当缓存不够用时采用的更新算法。只是选出的淘汰元素的规则不一样:LRU淘汰最久没有被访问过的,LFU淘汰访问次数最少的,FIFO先进先出。
一致性:要清理哪些数据是由具体的算法定的,开发人员只能选择其中的一种,一致性差。
开发维护成本:算法不需要开发人员维护,只需要配置最大可使用内存即可,然后选择淘汰算法即可,故成本低。
使用场景:适合内存空间有限,数据长期不变动,基本不存在数据一不致性业务。比如一些一经确定就不允许变更的信息。
2、超时剔除
给缓存数据手动设置一个过期时间,比如Redis expire命令。当超过时间后,再次访问时从数据源重新加载并设回缓存。
一致性:主要处决于缓存的生命时间窗口,这点由开发人员控制。但仍不能保证实时一致性,估一致性一般。
开发维护成本:成本不是很高,很多缓存系统都自带过期时间API。比如Redis expire
使用场景:适合于能够容忍一定时间内数据不一致性的业务,比如促销活动的描述文案。
3、主动更新
如果数据源的数据有更新,则主动更新缓存。
一致性:三者当中一致性最高,只要能确定正确更新,一致性就能有保证。
开发维护成本:这个相对来说就高了,业务数据更新与缓存更新藕合了一起。需要处理业务数据更新成功,而缓存更新失败的情