搜索
写经验 领红包
 > 时尚

缓存常见问题及解决方案有哪些(缓存常见问题及解决方案怎么写)

导语:缓存常见问题及解决方案

为了高性能、高并发、保护数据库,缓存在开发中经常使用,在给我们带来便利的同时如果使用不当会带来不少的badcase。其相关的问题也是面试中常谈的,如缓存穿透、缓存击穿、缓存雪崩、缓存预热等。本文简单梳理下相关问题。

什么是缓存

缓存很常见了,有本地缓存、分布式缓存等等,但很少看到有对缓存的定义。根据其特性尝试给缓存下个定义:

1、凡是位于速度相差较大的两种介质之间,用于协调两者数据传输速度差异的结构,都可以称为缓存。

2、缓存是一种设计模式,其利用增加存储空间的方式,实现低速部件与高速部件之间的解耦。只要是实现了解耦的地方就有存在缓存的可能。

3、缓存用空间换时间解决问题,空间不可无限使用,因此需要考虑如何节省空间、如何提高缓存命中率、如何确定有效的更新策略等问题。

缓存穿透

定义:

缓存穿透是指查询一个一定不存在的数据时,每次都会“穿过缓存”查询数据库。

这是由于缓存是不命中时被动写入的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。如数据被删除、接口被攻击等。

解决方案:

1)缓存空值:没有数据也是一种状态,把这种状态也放到缓存中,避免穿透。

优点:实现简单 缺点:空值也占用内存资源,尤其在接口被攻击时会有很多数据是查不到的。

2)布隆过滤器

优点:效果好,节省空间 缺点:实现复杂度较高

布隆过滤器认为不在的,一定不会在集合中;布隆过滤器认为在的,可能在也可能不在集合中。

缓存击穿

定义:

缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设置到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

解决方案:

1)使用互斥锁(mutex key)。在缓存失效的时候,不立即去查询数据库,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再查询数据库并设置缓存,之后再清除互斥锁;如果查询到互斥锁已存在,则等待后再查询。

2)热点数据永不过期,不设置过期时间。

缓存雪崩

定义:

缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,请求直接落到数据库上,引起数据库压力过大甚至宕机。(这个和缓存击穿的区别在于缓存击穿针对某一key缓存,缓存雪崩是很多key)

解决方案:

1)均匀过期:设置不同的过期时间,让缓存失效的时间点尽量均匀。通常可以为有效期增加随机值或者统一规划有效期。(比较常见)

2)加互斥锁:跟缓存击穿解决思路一致,同一时间只让一个线程构建缓存,其他线程阻塞排队。

3)缓存永不过期:缓存在物理上永远不过期,用一个异步的线程更新缓存。

4)使用限流&降级策略保护数据库。

缓存预热

缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统,这样就可以避免在用户请求的时候,先查询数据库,然后再将数据回写到缓存。如果不进行预热, 缓存初始状态数据为空,系统上线初期,对于高并发的流量,都会访问到数据库中,对数据库造成流量的压力。

具体方案:

1)数据量不大的时候,项目启动的时候进行加载缓存动作;

2)数据量大的时候,设置一个定时任务脚本,进行缓存的刷新;

3)数据量太大的时候,优先保证热点数据进行提前加载到缓存。

我们之前有个场景是系统所有接口要做一次用户id的转换,这个转换很容易成为系统的瓶颈,当时搞活动紧急的做法就是缓存预热,提前使用脚本将转换好的数据存入redis集群,当时有七亿多数据,不过每条数据字段很少,不是特别占内存。

缓存降级与限流

短时间范围内牺牲一些客户体验,限制一部分请求访问,降低应用服务器压力,待业务低速运转后再逐步放开访问。

本文内容由快快网络小梓整理编辑!