1.内存淘汰
当内存不足时自动淘汰部分数据,下次查询时更新缓存。
2.超时剔除
给缓存数据添加ttl时间,到期后自动删除缓存。下次查询时更新缓存。
3.主动更新
编写业务逻辑,在修改数据库的同时,更新缓存
业务场景:
低一致性需求:内存淘汰策略。
高一致性需求: 主动更新,并以超时剔除为兜底方案。
缓存更新时会遇到的问题有哪些?
1.缓存穿透
缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。如果大量的请求打到数据库上给数据库带来很大的压力,甚至可能会出现宕机的情况。
解决方案:
1.缓存空对象
如果你访问的数据redis和数据库都没有,我就赋一个空值,下次来访问的时候就不至于缓存失效,但是这有一个问题,就是要给空值赋予一个过期时间,因为访问的数据在数据库中出现的时候,就要更新到redis当中。否则就会出现短期不一致的问题。除此之外,还会产生额外的消耗。
2.布隆过滤
布隆过滤器是一串二进制数组和一系列的哈希函数。如下图所示:
如果我们要插入一个数据你好,首先由n个哈希函数(不同的hash算法)计算hash值,然后落位到相应的数组下标,对应的数据下标都为1。如果我们要查询你好,则看这些数组下标对应的值全为1,则表明存在。如果要删除,则会出现误删的情况。
讲一讲布隆过滤器的优点:
1.占用空间非常小。由一串二进制数组组成的数据
2.插入和查询都是非常快的。
缺点是:
误判。误判是不可避免的。在布隆过滤器源码中,会传入三个参数,有两个参数是跟误判率有关系,一个是size,一个是k。误判率不能设置的无限小,计算时间长,性能低。
在缓存这里布隆过滤器是在请求和redis之间,首先通过布隆过滤器是否存在,如果不存在,则拒绝,存在继续访问redis。
2.缓存雪崩
缓存雪崩是指同一时段大量的缓存key同时失效或者redis服务宕机,导致大量的请求到达数据库,带来巨大的压力。
解决方案:
(1).针对于大量的key同时失效,给不同的key的ttl添加随机值
(2).针对于redis宕机,我们使用redis集群提高服务的可用性
(3).给缓存业务添加降级限流策略(当redis集群都失效了,快速失败)
(4).给业务添加多级缓存(nginx,tomcat,jvm,redis,mysql)
3.缓存击穿
缓存击穿问题也叫热点key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。
解决方案:
首先聊一下正是因为热点key突然失效,并且缓存重建较为复杂。所以引入互斥锁来解决大量的请求缓存重建给数据库带来压力。一次只有一个线程进来缓存重建,其他线程等待。引入逻辑过期来解决key突然失效的问题。
(1).互斥锁
使用synchronized互斥锁的形式加互斥锁,确保一次只有一个线程。这样的优点是
1.没有额外的内存消耗
2.保证一致性
3.实现简单
缺点是
(1)线程需要等待,性能受影响
(2)可能有死锁风险
(2).逻辑过期
这个逻辑过期并不是真的过期,是通过给对象添加一个expire字段,这个字段值比如在当前时间+30,判断如果当前时间大于expire,这个时候就过期了,这个时候先获取锁,然后开启一个新线程进行缓存重建,当完成的时候,这个新线程释放锁。下图为缓存重建的流程图。
首先从redis当中,查询商铺信息,判断是否命中,如果未命中,返回空。如果命中,判断是否过期,如果过期,尝试获取互斥锁,开启新线程,缓存重建并释放锁。如果没有获取到锁,直接返回商铺信息。如果未过期,返回商铺信息。