1.什么是缓存穿透、缓存击穿、缓存雪崩?你们在项目中是怎么解决的?

缓存穿透:是指查询一条在redis不存在,在数据库也不存在的数据。如果不采取措施,大量的请求访问一个不存在的数据,会加大我们服务器压力。

解决:在项目中我们大致使用过两种办法。一是采用布隆过滤器,因为布隆过滤器会在所有请求达到缓存之前拦截,他会去查询这条数据是否存在。布隆过滤器最大特点就是查询速度快,他告诉你存在可能并不真的存在,他告诉你不存在那一定不存在。
二是缓存空值,通过在yml中配置Redis可以缓存空值,这样只要我们查询到的数据不存在,就缓存一条数据Value为空到Redis,下次再请求直接给请求返回空。

缓存击穿:查询一条Redis中不存在,但是数据库中存在的数据。

解决:同样有两种方案。一:设置热点数据永不过期,热点的数据不应该加过期时间,如果刚好过期就有大量请求来访问,会极大的增加服务器的压力。
二:同步锁。不考虑分布式的情况下可以使用Cache自带属性sync做到同步加锁,如果考虑分布式可以使用Redisson加读写锁。加锁之后,只让第一个请求去查数据库,查到之后放到缓存中,后面的请求去缓存中拿。

缓存雪崩:类似于缓存击穿,只不过是大量的请求在同一时间过期,导致所有请求都到数据库去查。

解决:一:和缓存击穿一样,热点的数据不应设置过期时间,避免导致大量请求直接访问数据库。
二:当在为缓存设置过期时间的时候,应在原基础上加上一个随机时间,避免同时过期。第二条使用的时候必须配合第一条一起使用,因为可能加了随机时间之后反而导致一部分数据的过期时间相同,在淘宝等数据量,请求量够大的情况下,一定会导致部分热点数据同时过期,所以需要配合第一条一起使用。

2.什么是缓存双写一致性?如果避免出现一致性问题?

概念:在多线程的情况下,多个线程同时对数据库和缓存进行写操作,如果某个线程出现网络问题,就会导致数据库和缓存的数据不一致。
解决: ①先删缓存,再更新数据库
采用延时双删来避免,进来先删一次缓存,更新完数据库之后线程睡一会儿,再删缓存
②先更新数据库,再删除缓存
方案一:采用分布式锁Redisson的读写锁,来保证整个操作没有执行完之前,其他线程不能进来
方案二:采用Alibaba的canal。canal是借助mysql的Binlog机制,伪装成mysql的一个从库,当主库数据发生变化时,会同步增量更新到缓存中。

一般建议使用第二种,因为第二种出现双写一致性的概率比较低。