缓存雪崩、缓存击穿、缓存穿透详解

缓存雪崩、缓存击穿、缓存穿透详解以及区别和解决方案

1. 缓存雪崩

1.1 什么是缓存雪崩?

缓存雪崩指的是由于缓存服务器在同一时间大面积失效或宕机,导致大量请求直接访问数据库,瞬间引发数据库压力激增,甚至导致数据库崩溃。

1.2 造成缓存雪崩的原因
  • 同一时间大量缓存失效:如果缓存设置了相同的过期时间,到了某个时间点,大量缓存同时失效,所有请求直接访问数据库,造成数据库压力骤增。
  • 缓存服务器宕机:缓存服务器因故障无法提供服务,导致请求全部直接访问数据库。
1.3 解决方案
  1. 缓存过期时间设置为随机值
    • 不要让所有缓存同时过期,可以通过设置缓存的过期时间为随机值来避免。
    • 例如,缓存的过期时间 TTL 设为一个基准值加上一个随机的时间偏移量。
redisTemplate
	.boundValueOps(DOCTOR_CACHE+doctorId)
	.expire(
		DOCTOR_CACHE_EXPIRE + 
		new Random().nextInt(7200), 
		TimeUnit.SECONDS
	);
  1. 加固缓存系统
    • 使用分布式缓存架构,避免单点故障。常用的分布式缓存有Redis Cluster、Memcached等。
    • 为缓存服务配置备份节点和集群架构,防止因缓存宕机引发系统崩溃。
  1. 限流降级(nginx IP限流)
    • 在缓存失效时,对请求进行限流,防止过多请求涌入数据库。可以通过限流器(如漏桶算法、令牌桶算法)等方式来控制请求量。
    • 同时,在缓存不可用时可以返回一些默认值或者降级的数据。

2. 缓存击穿

2.1 什么是缓存击穿?

缓存击穿是指某个热点数据在缓存中失效的瞬间大量的并发请求同时访问该数据,由于该数据在缓存中失效,大量请求同时访问数据库,造成数据库压力骤增。这种情况通常发生在热点数据或访问频繁的数据上。

2.2 解决方案
  1. 互斥锁(Mutex)机制:
    • 缓存失效时,通过加锁的方式保证只有一个线程去查询数据库并更新缓存其他线程等待缓存更新完成后再获取数据
  1. 预加载缓存:
    • 对一些热点数据提前加载,并定期刷新缓存,防止缓存失效。
  1. 使用不过期的缓存:
    • 对于极为重要的热点数据,可以设置其缓存永不过期,同时后台启动线程定期刷新该缓存
  1. 物理上不设置失效时间,逻辑控制(代码层面控制)

3. 缓存穿透

3.1 什么是缓存穿透?

缓存穿透是指客户端频繁访问一些根本不存在的缓存数据,由于缓存中没有这些数据的记录,每次请求都直接访问数据库,导致数据库压力增大,但是数据库中也不存在。

这通常是由于用户输入非法或恶意构造的请求引发的。

3.2 解决方案
  1. 缓存空值(缓存空标记)
    • 当查询一个不存在的key时,先访问缓存,缓存中没有访问数据库,数据库中也没有用redis做一个空标记 ,将空结果也写入缓存,并设置一个较短的过期时间 。下次再遇到相同的请求时判断是否存在空标记 key,存在这个空标记则直接返回缓存中的空值,避免再次查询数据库。
    • 存在问题:当这种空标记过多,会消耗资源,所以这种情况采用布隆过滤器
  1. 布隆过滤器(Bloom Filter)
    • 在查询缓存和数据库之前,利用布隆过滤器来存储这个 key ,判断key是否存在。
    • 存在则直接放行;
    • 如果该key不存在则直接被拦截返回,不必查询缓存或数据库,节约存储空间。
  1. 限流降级(nginx IP限流)
    • 在缓存失效时,对请求 IP 进行限流,防止过多请求涌入数据库。可以通过限流器(如漏桶算法、令牌桶算法)等方式来控制请求量。
    • 同时,在缓存不可用时可以返回一些默认值或者降级的数据。
  1. 参数校验(前端参数检验)
    • 在系统前端或者应用层对请求的参数进行有效性验证,过滤掉明显无效或恶意的请求。

4. nginx 限流算法

1. 令牌桶算法

令牌以固定速率产生,并缓存到令牌桶中;

发起的请求队列要消耗同等比例的令牌才能被处理;(只有拿出对应比例的令牌才能执行对应数量的请求)

令牌桶放满时,多余的令牌被丢弃;

令牌不够时,请求被缓存。

2. 漏桶算法

请求从上方倒入漏桶,从漏桶下方流出处理;
来不及处理的请求会在漏桶中进行缓冲(缓存),这些请求以固定速率流出;
漏桶满后,也就是请求溢出则直接丢弃。


算法的核心缓存请求、匀速处理、多余的请求直接丢弃

漏桶算法令牌桶算法 不同之处

令牌桶算法不但有一只“桶”,还有个队列,这个桶是用来存放令牌,队列才是用来存放请求的;

漏桶算法则是将请求直接缓存放在“桶”中。

5. 总结分析方案以及区别

  • 缓存雪崩:通过设置随机过期时间、使用分布式缓存和限流降级来应对。
  • 缓存击穿:通过互斥锁、预加载缓存(缓存预热)等手段解决热点数据失效引发的数据库压力。
  • 缓存穿透:通过缓存空值、使用布隆过滤器和参数校验来防止无效请求访问数据库。

名称

区别

解决方案

缓存雪崩

由于缓存服务器在同一时间大面积失效或宕机,导致大量请求直接访问数据库,瞬间引发数据库压力激增,甚至导致数据库崩溃

缓存过期时间设为随机:不要让所有缓存同时过期,可以通过设置缓存的过期时间为随机值来避免。例如,缓存的过期时间 TTL 设为一个基准值加上一个随机的时间偏移量。

加固缓存:为分布式缓存架构的缓存服务配置备份节点和集群架构,防止因缓存宕机引发系统崩溃。

限流降级:在缓存失效时,对请求进行限流,防止过多请求涌入数据库。可以通过限流算法漏桶、令牌桶等方式来控制请求量。同时,在缓存不可用时可以返回一些默认值或者降级的数据。

缓存击穿

数据在缓存失效的瞬间大量的并发请求同时访问该数据,造成数据库压力骤增

互斥锁:加锁的方式保证只有一个线程去查询数据库并更新缓存,其他线程等待缓存更新完成后再获取数据。

预加载缓存:对热点数据提前加载,并定期刷新缓存,防止缓存失效。

设置不过期缓存:对于极为重要的热点数据,可以设置其缓存永不过期,同时后台启动线程定期刷新该缓存。

逻辑控制失效时间:物理上不设置失效时间,逻辑控制(代码层面控制),如果一直访问就不断续期

缓存穿透

频繁访问一些根本不存在的缓存数据,由于缓存中没有这些数据的记录,每次请求都直接访问数据库,导致数据库压力增大,但是数据库中也不存在。

缓存空标记:当查询一个不存在的key时,先访问缓存,缓存中没有访问数据库,数据库中也没有就用redis做一个空标记 ,将空结果也写入缓存,并设置一个较短的过期时间 。再遇到相同的请求时判断是否存在空标记 key,存在这个空标记则说明数据不存在直接返回缓存中的空值,避免再次查询数据库。但是一旦这种空标记过多会消耗大量资源。

布隆过滤器(较优方案):在查询缓存和数据库之前,利用布隆过滤器来存储这个 key ,判断key是否存在。存在则直接放行; 如果该key不存在则直接被拦截返回,不必查询缓存或数据库,节约存储空间。

nginx ip 限流:在缓存失效时,通过 nginx 对请求 ip 进行限流,防止过多请求涌入数据库。可以通过限流算法漏桶、令牌桶等方式来控制请求量。同时,在缓存不可用时可以返回一些默认值或者降级的数据。

前端参数检验:在系统前端或者应用层对请求的参数进行有效性验证,过滤掉明显无效或恶意的请求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值