Redis引入带来的问题
针对这个问题 我们可以从两个方面回答
一、硬件成本的增加
Redis是依赖内存的,所以Redis的引入必然会对内存提出比较高的要求。
二、维护成本的增加
我们主要针对以下两个关键问题的维护进行说明
1、缓存失效
缓存没有能够发挥其应有的作用,可能是缓存过期等原因,导致透过缓存层对数据库造成压力
- 缓存穿透
缓存穿透是用户针对缓存和数据库中没有的数据进行不断的请求,从而造成数据库压力
如何解决缓存穿透:
- 在接口层增加校验。针对用户请求数据的合法性进行校验
2)如果查询不到数据,我们可以将查询的key 放到缓存中,value设置为null,从而降低数据库压力
3)使用布隆过滤器
- 缓存击穿
缓存击穿是指缓存中没有数据,但是数据库中确实存在数据(一般是缓存时间到期),由于并发导致数据库压力
如何解决缓存击穿:
针对一些特殊要求的数据可以设置为永不过期
加互斥锁。请求时,如果没有数据,此时对该key加上互斥锁,由本次线程进行数据库查询,并更新缓存信息。
- 缓存雪崩
缓存雪崩是指缓存中大批量过期,进而导致缓存查询不到,请求全部进行数据库查询。与缓存击穿不同的时,缓存击穿针对的时并发查询同一条数据,缓存雪崩针对的不同数据过期
如何解决缓存雪崩:
- 缓存过期时间避免相同,防止统一时间大量数据缓存过期
2)如果是分布式部署的缓存,将热点数据均匀分布在不同的数据库中
3)设置热点数据永不过期
2、缓存数据与数据库数据不一致
常规做法:
1)更新数据时,先更新数据库,再删除缓存
- A线程先更新数据,此时还没有更新缓存
- B线程读取数据,可以直接从缓存中读取(错误数据)
2)更新数据时,先删除缓存,在更新数据库
- A线程先删除缓存,进行数据库更新操作,此时更新操作还没有提交
- B线程读缓存,没有则读取数据库,由于A还没有提交,读取的还是原来的数据(错误数据)
延时双删:
1)普通延时双删
- 先删除缓存,再更新数据库,固定时间后再将缓存删除。这样可以保证延迟时间后的数据正常读取
- 如果线程B 在更新数据库过程中读取,如图所示。依旧会读取到错误数据。但是这个数据只会影响到部分进程
2)加互斥锁的延迟双删策略
针对上述问题,我们可以对key加上互斥锁,此时由于加上了互斥锁,B/C进程均无法对该key进行数据库读取操作。数据更新完成后,我们再对缓存数据进行删除操作。
此做法牺牲了一定的性能,但是保证了数据的一致性。