Redis 5.x——缓存穿透、缓存击穿和缓存雪崩
缓存穿透、缓存击穿和缓存雪崩1、缓存穿透2、缓存击穿3、缓存雪崩1、缓存穿透首先我们来了解一下图所示的这个基本操作。当客户端发送数据请求的时候服务业务会执行MySQL数据库或者将结果返回给客户端当然这在并发量少的时候是没有任何问题的。如果并发量比较大每一次请求数据都要操作MySQL数据库那么就需要执行阻塞的IO操作。最简单、最廉价的办法就是缓存此时操作流程就会演变成如图所示的业务架构图。当客户端发送请求过来之后业务服务先去缓存中判断数据是否在Redis中。如果数据不在缓存中则去MySQL数据库查询然后把查询到的数据缓存到Redis中再把结果返回给客户端当下一次请求同样的数据时就可以直接从Redis获取数据避免了再去MySQL数据库查询这从很大程度上提升了程序的响应性能。需要注意的是当查询Redis中没有数据时该查询会下沉到数据库层同时数据库层也没有该数据当出现大量这种查询或被恶意攻击时接口的访问全部透过Redis访问数据库而数据库中也没有这些数据我们称这种现象为“缓存穿透”。缓存穿透会穿透Redis的保护让底层数据库的负载压力变大。如果大量请求查询的数据既不在缓存中也不在MySQL数据库中那么会造成每次的查询操作都会对数据库进行查询因为不存在的数据是没有办法缓存的于是就造成MySQL数据库承受高并发的查询请求如图所示。针对上面的问题这里列出两种解决方案在业务服务访问层对用户进行校验来判断是不是来自恶意用户的请求比如对请求参数进行校验和检查一段时间内请求同一个服务的次数。利用前面学习过的布隆过滤器将数据库层有关数据的键存储到布隆过滤器中以判断访问的键是否在底层的数据库中。如果在布隆过滤器中则查询缓存如果缓存没有则再次查询MySQL数据库如果布隆过滤器中没有则直接返回我们预先规定好的结果即可。在数据访问的第一层我们采用布隆过滤器过滤见图虽然不能完全避免数据穿透的现象但布隆过滤器已经可以将99.99%的穿透查询屏蔽在Redis层极大地降低了底层数据库的压力减少了资源浪费。我们也可以把布隆过滤器的层级放到缓存下一层当请求数据的时候先去缓存层获取。如果缓存里面有数据就直接返回结果如果缓存没有就去布隆过滤器判断相关数据的键是否在布隆过滤器中如果在就继续查询MySQL数据库如果不存在就直接返回不再进行数据库层级的查询。2、缓存击穿缓存击穿和缓存穿透从名词上很难区分开它们的区别主要是“穿透”表示底层数据库没有数据而且缓存层内也没有数据而“击穿”表示底层数据库有数据但是缓存层内没有数据。当热点数据的键从缓存中淘汰出去后大量访问同时请求这个数据就会将查询下沉到数据库层此时数据库层的负载压力增大我们称这种现象为缓存击穿。下图中出现了缓存击穿问题大量的数据请求下沉到了MySQL数据库。针对上面的问题这里列出两种解决方案热点键的过期时间设置为永不过期。利用互斥锁保证同一时刻只有一个客户端可以查询底层数据库的数据一旦查到数据就缓存至Redis内以避免其他大量请求同时穿过Redis去访问底层数据库。3、缓存雪崩缓存击穿说的是热点数据过期缓存雪崩说的是大面积的数据过期。缓存雪崩是指Redis中大量的键几乎同时过期然后大量并发的查询穿过Redis冲击到底层数据库上此时数据库层的负载压力会增大。相比于缓存击穿缓存雪崩更容易发生。在图中大量缓存同一时间过期造成了缓存雪崩问题。针对上面的问题这里列出两种解决方案在可接受的时间范围内随机设置键的过期时间分散键的过期时间以防止大量的键在同一时刻过期。比如之前大量键的过期时间都是1个小时现在就可以设置为不同的时间段比如1小时1分钟、1小时2分钟等。可以根据业务情况选择不同的随机因子。键的过期时间设置为永不过期根据实际业务情况而定。