缓存
缓存对于大型系统的性能是十分重要的。可以解决一些痛点问题:查询比较耗时并且比较频繁的数据,缓存起来可以减少数据库的压力,提高响应速度。但是缓存也有问题,缓存不是即时查询结果就牺牲了强一致性和时效性,为此缓存要进行有策略的更新和失效,这是一种妥协平衡,而且使得操作变得复杂。
- 常见问题
- 问题一、缓存穿透
- 一直访问一个数据库不存在的数据,导致查询缓存和数据库造成性能问题
- 解决
-
对请求参数做校验,比如用户鉴权校验,id做基础校验,id <= 0的直接拦截。
如果查询到数据库没有值,也将对应的key存进缓存中,value为null。这样下次查询就直接从缓存返回了。但这里的key的缓存时间应该比较短,比如30s。防止后面在数据库插入了这条数据,而用户获取不到。
使用布隆过滤器,判断一个key是否已经查过了,如果已经查过了,就不去数据库查询。
-
- 问题二、缓存击穿
- 一个key的访问量非常大,比如某秒杀活动,有1w/s的并发量。这个key在某一时刻过期,那这些大量的请求就会一瞬间到数据库,数据库可能会直接崩溃。
- 解决
- 对于热点数据,慎重考虑过期时间,确保热点期间key不会过期,甚至有些可以设置永不过期
- 使用互斥锁(比如Java的多线程锁机制),第一个线程访问key的时候就锁住,等查询数据库返回后,把值插入到缓存后再释放锁,这样后面的请求就可以直接取缓存里面的数据了。
- 问题三、缓存雪崩
- 原因
- 同一时间大量key同时失效
- 缓存服务器宕机
- 解决
- 对每个key的过期时间设置一个随机值,而不是所有key都相同
- 使用高可用的分布式缓存集群,确保缓存的高可用性,比如redis-cluster
- 原因
- 问题四、双写不一致
- 解决
- 读取的时候,先读取缓存,如果缓存中没有,就直接从数据库中读取,然后取出数据后放入缓存
- 更新的时候,先删除缓存,再更新数据库
- 解决
- 问题一、缓存穿透