缓存穿透
产生原因
缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会直接打到数据库上。即当查询一个一定不存在的数据时,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来压力。
产生影响
缓存穿透可能会被不法分子利用,通过发起大量的针对不存在的数据的请求,对数据库造成压力,甚至导致数据库崩溃。
解决方案
针对缓存穿透,有几种常见的解决方案:
-
缓存空对象
-
优点:实现简单,维护方便。
-
缺点:额外的内存消耗,因为缓存了一些不存在的数据对应的空对象。但可以通过给这些空对象设置较短的TTL(如60秒)来解决这个问题,但这样可能会造成短期的数据不一致。
-
-
使用布隆过滤器
-
优点:内存占用少。
-
缺点:实现复杂,且存在误判的可能性。布隆过滤器可以判断一个元素是否一定不存在于集合中,但无法判断元素一定存在。
-
-
其他方法
-
使用bitmaps类型定义访问白名单,或进行实时监控,和运维人员配合排查访问对象和访问数据设置黑名单限制服务。
-
应用场景
缓存穿透在多种场景下都可能出现,特别是在电商系统、金融系统、社交平台和新闻媒体网站等,当访问量激增或特定事件发生时,更容易出现缓存穿透的问题。因此,在这些系统中,需要特别关注缓存穿透的问题,并采取相应的解决方案来减轻对数据库的压力。
缓存穿透是一个需要重视的问题,它可能会对数据库造成严重的压力。通过合理的解决方案,如缓存空对象、使用布隆过滤器等方法,可以有效地缓解缓存穿透带来的问题,提高系统的稳定性和性能。
缓存雪崩
缓存雪崩是一个在分布式系统中,特别是使用了缓存技术(如Redis)的系统中可能遇到的问题。当缓存中的大量数据在同一时间过期失效,而此时又有大量的用户请求这些数据时,由于缓存失效,所有的请求都会直接打到数据库上,导致数据库压力骤增,甚至可能引发数据库宕机。
缓存雪崩的原因
-
缓存大面积的同时失效:这可能是由于缓存服务器宕机、缓存的key设置了相同的过期时间等原因导致的。
-
对热点数据的持续高并发:某些热点数据在缓存过期后,如果有大量的请求同时访问这些数据,也可能导致缓存雪崩。
缓存雪崩的影响
-
数据库压力过大:由于大量的请求直接访问数据库,可能导致数据库CPU和内存资源耗尽,进而影响数据库的正常运行。
-
系统性能下降:由于数据库响应速度变慢,整个系统的响应时间也会变长,用户体验下降。
-
可能引发系统崩溃:在极端情况下,如果数据库无法承受如此大的压力,可能会引发系统崩溃。
缓存雪崩的解决方案
-
避免缓存设置相近的有效期
-
为有效期增加随机值
-
统一规划有效期,使失效时间均匀分布
-
-
对热点数据的持续高并发
-
使用互斥锁、JVM锁机制或分布式锁机制
-
-
缓存永不过期,异步更新
-
优点:不阻塞线程,用户体验好,不会出现雪崩效应
-
缺点:不保证一致性,代码复杂度增大,容易规程垃圾数据
-
-
其他策略
-
加锁排队:使用Redis的setnx去set一个mutex key,当操作返回成功时,再进行load db并回设到缓存,否则就重试整个get缓存的方法。
-
数据预热:系统上线后,将相关的缓存数据直接加载到缓存系统。
-
双层缓存策略:C1为原始缓存,C2为拷贝缓存,C1失效时可以访问C2。
-
定时更新缓存策略:对失效性要求不高的缓存,容器启动初始化加载,采用定时任务更新或移除缓存。
-
通过实施上述解决方案,可以有效地缓解缓存雪崩带来的问题,提高系统的稳定性和性能。
缓存击穿
缓存击穿(Cache Breakdown)是另一个在缓存系统中常见的问题。它描述的是当某个热点数据(key)在缓存中不存在(过期或从未被缓存),而此时又有大量的用户请求这个数据,导致这些请求都会穿透缓存,直接请求到数据库上。由于数据库需要处理大量的请求,可能导致数据库压力过大,甚至崩溃。
缓存击穿的原因
-
热点数据过期:某些热点数据在缓存中过期后,如果有大量的请求同时访问这些数据,这些请求会穿透缓存,直接访问数据库。
-
缓存被误删除:由于某些原因(如误操作或缓存淘汰策略),缓存中的热点数据被提前删除,导致后续请求直接访问数据库。
缓存击穿的影响
-
数据库压力过大:由于大量的请求直接访问数据库,可能导致数据库CPU和内存资源耗尽,进而影响数据库的正常运行。
-
系统性能下降:由于数据库响应速度变慢,整个系统的响应时间也会变长,用户体验下降。
-
可能引发系统崩溃:在极端情况下,如果数据库无法承受如此大的压力,可能会引发系统崩溃。
缓存击穿的解决方案
-
热点数据不过期:对于热点数据,可以将其设置为永不过期,或者设置较长的过期时间,以减少缓存击穿的可能性。
-
使用互斥锁:当缓存失效时,不是立即去加载数据库,而是先使用互斥锁或某种队列来控制只有一个线程去加载数据库,其他线程只需要等待即可。当数据加载完毕后,再释放锁。此时,其他线程获取到锁后,从缓存中获取数据即可。
-
双缓存策略:使用两个缓存,当第一个缓存失效时,去访问第二个缓存。如果第二个缓存也存在失效的情况,那么此时再去加载数据库。这种策略可以在一定程度上减少缓存击穿的发生。
-
监控与预警:通过监控工具实时监控系统中的缓存状态,当发现某个热点数据的缓存命中率急剧下降时,及时发出预警,并采取相应的措施来避免缓存击穿的发生。
通过实施上述解决方案,可以有效地缓解缓存击穿带来的问题,提高系统的稳定性和性能。