一、缓存
缓存的作用一般是为了减轻数据库压力设计的,因为数据都是读写磁盘,当并发量大的时候,磁盘IO可能跟不上并发量。而缓存一般设计都是放在内存中的,最常见的例如redis和memcached,都是把数据都缓存在内存中。读写内存的速度比磁盘快很多,因此把常用的数据都放到内存中做缓存可以给数据库减轻很大的压力。
一个正常的缓存处理流程为:
- 先判断缓存中是否存在数据,如果缓存存在数据,直接读缓存中的数据。
- 如果缓存不存在,从数据库读数据。
- 如果数据库中存在数据,返回数据库中的数据并写到缓存。
- 如果数据库中也不存在数据,直接返回。
而作为缓存系统,需要考虑的几个问题是:缓存穿透、缓存击穿和缓存雪崩。
二、缓存穿透
缓存穿透:查询一个数据库不存在的数据,因为数据都不存在,所以缓存中也不存在,请求会直接去数据库中查询,这种情况就产生了缓存穿透。
例如对一个只含非负整数的表中查询id = -1
的记录,缓存中不存在数据,所以每次都会请求数据库。当有攻击者恶意使用这种方式频繁请求数据时,会给后端数据库造成极大的压力。
解决方案:
- 增加数据校验,直接过滤掉明显不存在的数据。这里一般采用布隆过滤器,预先生成所有可能的数据的bitmap,请求数据库前先在过滤器中查找,过滤掉不可能的数据。
- 对不存在的值也设置缓存,在数据库中查询到不存在的数据之后在缓存中添加一个
key=null
的值。
三、缓存击穿
缓存击穿:某个key缓存在某一时刻失效,由于请求量特别大,导致这一时刻的所有请求同时都直接请求数据库,给数据库带来巨大压力。
解决方案:使用互斥锁或者其它方法锁住这个key(单例模式),当有请求已经在查询这个key时,等待请求,这个请求完成后数据写入缓存再从缓存中读取数据。
四、缓存雪崩
缓存雪崩:给一些键值设置了过期时间,同一时刻这些数据同时失效,请求直接到达数据库。
解决方案:
- 和缓存击穿一样,使请求单例执行。
- 不要给缓存的过期时间都设置成一样的,设置超时事件的时候加上一个随机时间作为时间。
缓存雪崩和击穿其实一样,缓存击穿时缓存雪崩的一个特例。
两者的区别:缓存雪崩是指多个缓存数据同时失效,而缓存击穿特指某一个数据失效。
此处评论已关闭