1.为什么使用redis
1.1 问题背景
在实际应用场景中每一次进行查询服务的时候都需要访问数据,而数据存在于数据库中,我们就需要每次都将访问请求打到数据库中,这样大大加重了数据库负担,当并发量过大时还会导致系统崩溃宕机。
1.2 解决方式
首先,我们的方案选择redis,它是一个非关系型数据库,是以key-value形式存储数据的存储系统。第二,redis是存在于内存中的,这里就是牺牲空间来换取查询时间的一个思想,并且存放于内存中的数据读写速度都是很快的,还实现了数据持久化。总之,它能解决数据库负担的原因就是因为它用作缓存,1.可以减轻数据库压力 2.可以提高查询效率。
当数据库数据进行更新添加时,会刷新redis中存放的数据,作为当前数据的缓存,在进行访问请求的时候,就会先访问redis,如果redis中没有才会去访问数据库。
但是,这样也引发了一系列问题,缓存穿透,缓存击穿,雪崩。
2.什么是缓存的穿透,击穿,雪崩
2.1 什么是缓存穿透
缓存穿透:当用户要访问的数据在缓存中没有时,就会去访问数据库,并且查询完数据库后
发现连数据库中也访问不到数据,这就使后面的请求都会访问到数据库,这就是缓存穿透。
2.2 什么是缓存击穿
缓存击穿:当redis存储的某一数据过期后,有大量的请求需要获取这个过期的数据,那么
就会去直接访问数据库,这样使数据库压力剧增,这就是缓存击穿。
2.3 什么是雪崩
缓存雪崩:简单说就是缓存击穿的复数形式,当多个缓存同时过期或者redis出现故障时,
有大量请求要来访问这些数据,redis无法处理,从而把访问压力全部打到数据库中,可能
造成数据库崩溃导致系统崩溃的连锁反应,这就是缓存雪崩。
3.解决方案
3.1 缓存穿透
解决方式:1.非法请求限制 2.缓存空值或者默认值 3.布隆过滤器(吹底层即可)
这里我们实现了第二种方式当缓存中没有数据时,我们接下来要查数据库,在查数据库后,
若有数据直接设置数据即可,如果没有数据,也把查询出来的空值或者默认值也设置进去,
这样就实现了而后来的请求查询当前数据是有值的但是是个空值,这就解决了缓存穿透问题
3.2 缓存击穿
解决方式:使用互斥锁,先拦截所有请求,实现仅有第一个请求访问数据库资源,若缓存有
则直接返回,如果没有那么将查询数据库,并把数据设置到缓存中,而后的所有请求都不用
访问数据库了。
3.3 缓存雪崩
解决方式:1.均匀设置过期时间2.互斥锁 2.双key策略
1.这种方式可以使用最高响应比算法进行实现,设置一个记录位,记录访问次数,赋予权重
对每一次访问后过期时间都进行修改更新。还可以使用最佳平均等待时间算法进行实现。
2.互斥锁,这种方式和缓存击穿所用思想相同。
3.双key策略,设置一个主key一个备key,主key有过期时间,备key不会过期,当主备都
没有时才会访问数据库并设置双key缓存,当主key没有备key有时直接返回备key数据。
4. 部分面试题
1 你的项目中那个地方使用到了缓存? 为什么要用缓存?
车辆类型加载的时候使用到了缓存技术,使用缓存的目的是为了缓解数据库压力
让每一次发送的查询请求先在缓存中查找,也大大提高了查询效率,节省CPU调度资源
2 为什么要用redis缓存不用mybatis二级缓存?
mybatis二级缓存只适用于在当前项目中进行缓存,而我们的项目需要进行分布式缓存
,意味着当两个应用服务查询数据库时,有可能其中一个获取的本地缓存数据是没有进行
更新的,就会出现数据匹配不上问题,使用redis缓存就可以解决缓存不同步问题,数据库数据
会同步一份到redis中,每次查询直接访问redis获取数据即可。
3 用了redis缓存后有什么好处?
降低数据库压力,访问请求不用全部发送到数据库,直接在内存中获取
以空间换时间,效率高。
4 你是怎么实现缓存的?怎么做的
在项目中先配置redis,调用redisTemplate设置键值,过期时间。
用户请求车辆类型数据时,先在redis缓存中获取,如果有直接返回,如果没有则从数据库中
获取并设置redis缓存。当然这里会涉及到缓存穿透、击穿、雪崩问题。
5 项目中为什么不使用springcache
使用springcache能够快速的进行缓存实现,但是在缓存中存在问题如缓存穿透、击穿、雪崩
springcache并没有进行处理,所以需要我们自己实现缓存能有针对性的解决问题