在实际的项目开发中,用户的数据我们一般都使用数据库进行存储,其数据是存储在磁盘上的,虽然稳定,但I/O速度很慢,当用户量很多且有并发需求时,请求数量一上来数据库就很容易崩溃。
为了解决这一问题,Redis这一内存数据库得到了广泛的应用,将其作为缓存中间件,可以将磁盘数据库中的数据缓存在Redis上,从而相当于在内存上进行了缓存,可以大大提高读写速度,提高系统性能。
然而在缓存中,由于Redis和Mysql这类磁盘数据库速度的不匹配,会出现缓存异常的问题,其中缓存穿透、缓存击穿、缓存雪崩是需要考虑并解决的问题。
缓存穿透
问题描述
Key对应的数据并不存在,每次请求访问key时,缓存中查找不到,请求都会直接访问到数据库中去,请求量超出数据库时,便会导致数据库崩溃。如一个用户id不存在,数据库与缓存都不存在该id,此时黑客便可以利用此漏洞不断访问该id,造成数据库崩溃。
解决方案
①对空值缓存:如果一个查询数据为空(不管数据是否存在),都对该空结果进行缓存,其过期时间会设置非常短。
②设置可以访问名单:使用bitmaps类型定义一个可以访问名单,名单id作为bitmaps的偏移量,每次访问时与bitmaps中的id进行比较,如果访问id不在bitmaps中,则进行拦截,不给其访问。
③采用布隆过滤器:布隆过滤器可以判断元素是否存在集合中,他的优点是空间效率和查询时间都比一般算法快,缺点是有一定的误识别率和删除困难。
④进行实时监控:对于redis缓存中命中率急速下降时,迅速排查访问对象和访问数据,将其设置为黑名单。
缓存击穿
问题描述
key中对应数据存在,当key中对应的数据在缓存中过期,而此时又有大量请求访问该数据,缓存中过期了,请求会直接访问数据库并回设到缓存中,高并发访问数据库会导致数据库崩溃。
解决方案
①预先设置热门数据:在redis高峰访问时期,提前设置热门数据到缓存中,或适当延长缓存中key过期时间。
②实时调整:实时监控哪些数据热门,实时调整key过期时间。
③对于热点key设置永不过期。
缓存雪崩
问题描述
key中对应数据存在,在某一时刻,缓存中大量key过期,而此时大量高并发请求访问,会直接访问后端数据库,导致数据库崩溃。 注意:缓存击穿是指一个key对应缓存数据过期,缓存雪崩是大部分key对应缓存数据过期
解决方案
①构建多级缓存机制:nginx缓存+redis缓存+其他缓存。
②设置过期标志更新缓存:记录缓存数据是否过期,如果过期会触发另外一个线程去在后台更新实时key的缓存。
③将缓存可以时间分散:如在原有缓存时间基础上增加一个随机值,这个值可以在1-5分钟随机,这样过期时间重复率就会降低,防止大量key同时过期。
④使用锁或队列机制:使用锁或队列保证不会有大量线程一次性对数据库进行读写,从而避免大量并发请求访问数据库,该方法不适用于高并发情况。