Redis缓存相关问题
#redis #cache #db
缓存一致性
形成原因
数据增删修操作造成的缓存内容与持久层内容的不一致
解决办法
- 先更新缓存后更新数据库:更新缓存后程序异常终止或持久化失败导致数据未持久化
- 先更新数据库后更新缓存:更新数据库后程序异常终止或更新缓存失败导致缓存数据与数据库不一致。解决办法:先更新缓存,后将数据修改操作写入持久化队列,比如Kafka,让下游服务执行持久化操作
缓存穿透
针对多个key
形成原因
缓存穿透是指查询一个不存在的数据,由于缓存是不命中时,去存储层(如MySQL)查找数据。如果从存储层查不到数据没有写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,导致缓存穿透。流量一旦大了之后,容易导致DB宕机,进而影响整个业务。利用不存在的key频繁攻击应用,这就是漏洞。
解决办法
- 使用布隆过滤器,如果从DB中没有查到则添加到布隆过滤器中。但由于布隆过滤器中存储的内容是不能修改的,需要注意使用场景。如果当前查询不存在的
key
以后会出现再实际数据中,使用布隆过滤器会导致改条数据无法查询到。 - 缓存不存在的
key
,如果从DB中没有查询到该数据,则将对应的key
写入缓存中,并加一个合适的过期时间。value
内容写一个不存在的标记,当程序读到该内容后,即知道这条key
不存在对应的内容直接返回,不会将流量打入存储层。
缓存雪崩
多个key相同的过期时间
形成原因
缓存雪崩是指多个key在相同时间过期,导致缓存在某一时刻同时失效。请求全部转发到DB,DB瞬时压力过高宕机导致服务不可用。
解决办法
- 使用队列,将需要缓存的数据发往一个统一的队列中,依次写缓存。
- 随机过期时间,比如一个
key
需要缓存一小时,则在一小时的基础上随机±5分钟,这样可以一定程度上解决一批key
集中过期的问题
缓存击穿
针对一个key
形成原因
某个设置了过期时间的key
,在过期后某一时间有大量并发请求进来。而在第一个请求进来,从DB中查完还没来得及写入缓存中时后面的并发请求也进来了,就会造成同一个key
并发访问DB,瞬间打垮存储层。
一般突然出现的热点key
容易造成这种问题。
解决办法
- 使用分布式互斥锁,当一个
key
在缓存中没有查询到时,先去抢这个key
的锁,抢到则去存储层进行查询,没有抢到则去缓存中查询,根据实际情况如果一次没有查找到可以循环查找几次(毕竟查数据库需要耗时)。
其他
数据的缓存策略,有时也需要根据实际业务来设定。比如一些热点key
设置为永不过期,但永不过期也会给缓存的存储带来压力,而给key
设置过期时间,又会带来以上几种问题。抑或是缓存设置永不过期,使用异步线程定期删除一些没有访问的key
。
写代码的时候需要一个指导思想,但同时亦不可死搬教条。