赞
踩
在实际的业务场景中,Redis 一般和其他数据库搭配使用,用来减轻后端数据库的压力,比如和关系型数据库 MySQL 配合使用。
Redis 会把 MySQL 中经常被查询的数据缓存起来,比如热点数据,这样当用户来访问的时候,就不需要到 MySQL 中去查询了,而是直接获取 Redis 中的缓存数据,从而降低了后端数据库的读取压力。如果说用户查询的数据 Redis 没有,此时用户的查询请求就会转到 MySQL 数据库,当 MySQL 将数据返回给客户端时,同时会将数据缓存到 Redis 中,这样用户再次读取时,就可以直接从 Redis 中获取数据。流程图如下所示:
当我们使用缓存时,目标通常有两个:第一,提升响应效率和并发量;第二,减轻数据库的压力。
而本文中所提到的这三种场景:缓存穿透、缓存雪崩和缓存击穿的发生,都是因为在某些特殊情况下,缓存失去了预期的功能所致。
当缓存失效或没有抵挡住流量,流量直接涌入到数据库,在高并发的情况下,可能直接击垮数据库,导致整个系统崩溃。
这就是我们需要知道的大前提,而缓存穿透、缓存雪崩和缓存击穿,只不过是在这个大前提下的不同场景的细分场景而已。
缓存穿透是指当用户查询某个数据时,Redis 中不存在该数据,也就是缓存没有命中,此时查询请求就会转向持久层数据库 MySQL,结果发现 MySQL 中也不存在该数据,MySQL 只能返回一个空对象,代表此次查询失败。如果这种类请求非常多,或者用户利用这种请求进行恶意攻击,就会给 MySQL 数据库造成很大压力,甚至于崩溃,这种现象就叫缓存穿透。
注:虽然查询数据库为空,但是sql语句已经执行了,只要sql语句执行就会给mysql增压,特别是复杂的查询有时候会特别消耗cpu,cpu爆满直接就宕机了!
缓存穿透发生的场景一般有两类:
总体来看,计算机解决问题的思路无非就两个:空间换时间,时间换空间。当然,目前的算法都集中于空间换时间。
当 MySQL 返回空对象时, Redis 将该对象缓存起来,同时为其设置一个过期时间
。当用户再次发起相同请求时,就会从缓存中拿到一个空对象,用户的请求被阻断在了缓存层,从而保护了后端数据库,但是这种做法也存在一些问题,虽然请求进不了 MySQL ,但是这种策略会占用 Redis 的缓存空间
。缓存预热:是指系统启动时,提前将相关的数据加载到 Redis 缓存系统中。这样避免了用户请求的时再去加载数据。
缓存击穿是指用户查询的数据缓存中不存在,但是后端数据库却存在,这种现象出现原因是一般是由缓存中 key 过期导致的。比如一个热点数据 key,它无时无刻都在接受大量的并发访问,如果某一时刻这个 key 突然失效了,就致使大量的并发请求进入后端数据库,导致其压力瞬间增大。这种现象被称为缓存击穿。
缓存雪崩是指缓存中大批量的 key 同时过期,而此时数据访问量又非常大,从而导致后端数据库压力突然暴增,甚至会挂掉,这种现象被称为缓存雪崩。它和缓存击穿不同,缓存击穿是在并发量特别大时,某一个热点 key 突然过期,而缓存雪崩则是大量的 key 同时过期,因此它们根本不是一个量级。
所以,缓存雪崩的场景通常有两个:
缓存雪崩和缓存击穿有相似之处,所以解决方案都是互通的。
很多人会把缓存穿透和击穿搞混,主要是名词方面的混淆。更多的,我觉得关注意思即可。
缓存穿透与击穿的区别:
提起来穿透我们就去想象王者荣耀的破甲碎星锤,无视防御装备,因为缓存压根没有,并且数据库也没有,所以直接打真伤。
缓存击穿可以规避,因为只是 redis 缓存数据失效了,而数据库里有数据,只要把数据库里的数据更新到 redis 上,那么就可以解决掉缓存击穿的问题。
但是,缓存穿透,意味着,这个数据,数据库里也没有。所以,就不可能会把数据存到 redis 缓存里,因此只要有人来查询,就一定缓存中查不到,所以就一定要走数据库。那么,假设很多人,故意去查那些数据库里也没有的记录,我们的 redis 就起不到屏障的作用,因为 redis 里不可能有数据,所以并发查询就一定会打到数据库的身上。那么,想要解决缓存穿透,就必须想办法,能够识别出,哪些请求的数据,是数据库没有的,然后,对这些请求的查询,进行过滤。
而缓存雪崩更多的指多处被击穿这才引发的雪崩。
针对不同的缓存异常场景,可选择不同的方案来进行处理。当然,除了上述方案,我们还可以限流、降级、熔断等服务层的措施,也可以考虑数据库层是否可以进行横向扩展,当缓存异常发生时,确保数据库能够抗住流量,不至于让整个系统崩溃。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。