使用缓存的意图
连CPU这种每秒G级指令的玩意都使用高速缓存,那么分布式系统使用缓存不是也很正常么 ?
image.png
按照冯诺依曼架构来思考如今的计算机系统,不难发现,我们的web服务相当于计算核心,后端数据存储相当于硬盘,而缓存相当于内存。
缓存的特性,在于高速读写,但是不持久化。高速读写,起到的作用就是可以在很快的时间内响应一些静态数据查询,为后端存储提供一层查询保障。众所周知,后端存储的读性能是有瓶颈的,而且瓶颈比内存数据库要低很多,一旦超越这个阈值,有可能引起业务中断进而影响系统的可用性。
缓存读写策略
image.png我们在形成缓存数据的时候,避免不了要对数据进行update。这个时候我们应该采取更新数据之后失效缓存的操作,而不是数据库和缓存同时更新的策略,缓存按需加载,这样在更新逻辑上不仅简单了,也能轻易地保持一致性。
实际应用中,我们为了使得缓存相对较为准确,所以都采取了写缓存的时候使用失效时间。而这又引起了另一个问题,就是同一时间大量Key的失效,会引起缓存击穿。
应对击穿问题,那么我们采用的缓存失效时间,是随机生成的,而不是定长的。
分布式缓存系统高可用方案
(1)数据分片、一致性hash
我们可以很好地理解,使用Redis集群存储,并使用数据分片的情况下,如果某一节点挂了,那么其他节点的数据还在运行,不至于导致业务中断。集群就很好地保证了高可用性。
或者我们使用一致性hash算法,确定key的存储节点。一致性hash,将hash的值生成到一个范围之内,按照区间的方式定义存储节点,每次计算出的值顺着环去找到一个最近的存储节点存储。当然,它的问题在于容易引起雪崩故障,当某个cache节点挂了之后,流量将会冲击下一个节点,这时候下一个节点将会面临2倍的流量。因此我们要做好cache的高可用性,cache节点亦可以是cache集群。
数据分片,就像是HashMap一样,找到节点;一致性hash,将节点扩散到区间,由存储节点管理区间。
(2)中间代理层
除了分片之外,我们可以将这个方案抽象成一个中间代理层,由它负责去管理路由到Redis存储的哪个节点。这个方案,类似于多数据库聚合方案,比如mycat。
image.png
(3)Redis Sentinel
image.png
Redis提供的哨兵集群方案,它能监控多个master-slave集群,发现master宕机后能进行自动切换。
缓存穿透
缓存的作用核心参数,是缓存命中率,如果命中率太低则大量的查询流量穿透到db上,db支持的qps和tps都比较低,如果db挂掉的话,就会引起业务中断。因此,保证缓存命中率是核心考虑点。
如果系统只考虑查询到的数据写入缓存,那么大量查询不存在的数据则直接穿透到db中,所以我们可以使用两种方式来预防这种穿透:
(1)回种空值(2)布隆过滤器
我们可以在查询不到值的请求回写缓存一个空置,但如果是恶意攻击撞库,那么将会大量缓存写入,导致缓存容量超限而引起缓存集群故障。
一个更优秀的方案就是布隆过滤器。布隆过滤器可以鉴定一个数据是否在一个集合中,主要思路是hash算法,存在少量的误差率。使用这个方案,可以过滤掉不存在的元素的查询,这样就不会大量穿透了。
网友评论