3、缓存
3.缓存
3.0 缓存分类
只读缓存:缓存只负责读,任何写操作都会直接操作在数据库上,然后删除缓存里的数据,然后下次再请求数据时,发现缓存内没有,则重新请求数据库,这样缓存内存在的数据仍为新数据。
读写缓存:读写缓存,顾名思义,其写操作也会落到缓存上,会在缓存中进行修改,但是我们要考虑这个情况,那就是我们修改了缓存,数据库宕机的情况。则会造成数据不一致的情况。
然后写入数据库的时机有两种形式,一种是同步写回,一种是异步写回。
同步写回则是,缓存修改之后,立刻修改数据库,这样可能降低响应速度,但是能够保证安全性,这里我们就需要使用事务来搞定。一起执行才行,不然就会产生数据不一致的情况。
异步写回:则会缓存修改之后,找机会再进行修改数据库。
3.1 缓存淘汰机制
在设置了过期时间的数据中进行淘汰
随机淘汰(random)
LRU(随机选取N个值,然后在这N个值里选择最久未使用的)
LFU(使用次数最少)
TTL根据过期时间淘汰,越早过期的越删除
所有范围内进行淘汰
LRU
LFU
随机
如何处理被淘汰的数据
如果数据是干净数据,则直接淘汰,如果数据是脏数据,则需要先写入数据库,然后再进行淘汰,不过Redis 使用的是修改完之后,直接写入数据库,所以不会出现清理缓存的时候出现脏数据的情况。
推荐阅读:https://zhuanlan.zhihu.com/p/343963744
3.2 如何解决缓存和数据库内容不一致的问题
一致性
缓存中有数据,那么需要和数据库一致
缓存中没有数据,那么数据库中的就是新数据
单线程环境下
消息队列
我们可以使用消息队列来搞定,将待修改的值存入消息队列,如果修改成功则删除消息队列里的数据,如果失败,则从消息队列中取出,然后继续修改。含义则是重试
我们平常开发中,应该优先使用先更新数据库再删除缓存的方法,这样能够减小数据库压力。因为先删缓存会有缓存缺失的情况。
多线程环境下
这种情况,则会出现新的问题,我们思考一下,当A线程修改了数据库,然后写入缓存,此时B线程又修改了数据库,则会导致缓存中存的仍然是旧值。还会有另外三种情况,如果在并发环境下,如果是读写问题,则会对业务影响不大,但是写写问题则会影响很大,所以这里我们可以借助分布式锁
redlock来解决该问题。
推荐阅读:https://www.jianshu.com/p/a8eb1412471f
3.3 缓存穿透,缓存雪崩,缓存击穿
缓存雪崩
是指缓存中大量键到期,而查询量过大,发现缓存中没有该键,则会去请求后台,引起数据库压力过大甚至宕机。
解决方案
过期时间设置为随机,这样就不会出现短时间内大量过期的情况。
使用分布式数据库,分别请求不同的数据库,则会减少某一数据库的压力。
设置热点数据永远不过期
核心数据可以访问数据库,非核心直接返回,进行一个降级
缓存击穿
缓存击穿是指,针对某个访问非常频繁的热点数据的请求,无法在缓存中进行处理,紧接着,访问该数据的大量请求,一下子都发送到了后端数据库,导致了数据库压力激增,会影响数据库处理其他请求。
- 设置热点数据永远不过期
缓存穿透
缓存雪崩和缓存击穿都是因为键过期的情况,虽然缓存中没有该数据了,但是数据库中还有,虽然会对数据库造成压力,但是还是有机会解决。
情况如下,我们访问缓存时,发现缓存中没有该数据,则去查找数据库,发现数据库中也没有该数据,这样就会给缓存和数据库造成很大的压力。
发生这种事情有两种情况
误删除:被管理员一不小心将缓存中和数据库的数据都删了
恶意攻击:另一种情况就是被别人恶意攻击,故意拿数据库和缓存中没有的数据进行发出请求。
设定空值和缺省值
使用布隆过滤器判断是否含有该键,多用于缓存更新较少的情况,因为需要同步更新布隆过滤器
入口处检测(前端界面过滤,过滤掉部分)
注:布隆过滤器的原理:使用N个哈希函数,得出N个哈希值,并将哈希表的N个位置标记成 1,如果已经为 1 则无需标记,判断值是否存在时,计算N个哈希值,对应的位是否存在 0 ,存在 0 则表明该值不存在。
推荐阅读:https://www.cnblogs.com/xuanyuan/p/13665170.html
3.4 缓存污染
缓存污染的含义:某些不常被访问的数据,白白浪费内存空间
解决方法则是利用我们的缓存淘汰策略。我们来分析一下各个缓存淘汰策略
能不能解决缓存污染的情况
LRU 不能解决,他可以解决最久未访问的键,但是有些不常用的键,可能会偶尔被访问一次。
LFU最近最少使用,在使用时间和使用次数上都有要求,所以则可以解决缓存污染的情况。
LFU原理,使用一个字符串,然后前半部分保存时间戳,后半部分保存使用次数。
3.5 缓存的过期删除策略
定期删除:Redis 每隔一段时间(默认 100ms),就会随机选出一定数量的数据,检查它们是否过期,并把其中过期的数据删除,这样就可以及时释放一些内存。
惰性删除:当一个数据的过期时间到了以后,并不会立即删除数据,而是等到再有请求来读写这个数据时,对数据进行检查,如果发现数据已经过期了,再删除这个数据。
