首页 > 其他分享 >什么是缓存穿透、缓存击穿、缓存雪崩与其解决方案

什么是缓存穿透、缓存击穿、缓存雪崩与其解决方案

时间:2025-01-16 23:31:55浏览次数:3  
标签:缓存 capacity self 击穿 param 雪崩 哈希 数据库

目录

​缓存穿透

缓存击穿

缓存雪崩


缓存穿透:无效请求绕过缓存访问数据库。

缓存击穿:某个热点数据缓存失效,导致并发请求直接访问数据库。

缓存雪崩:大量缓存同时失效,导致请求集中访问数据库,数据库压力骤增

缓存穿透

定义:缓存穿透指的是查询一个根本不存在的数据,这种查询会绕过缓存直接访问数据库,导致大量无效的请求直接打到数据库,降低系统性能。

原因

  • 请求的数据不存在于缓存或数据库中。

  • 系统没有做有效的参数校验,导致无效请求未能被拦截。

解决方案

  • 参数校验:对所有输入参数进行有效性检查,避免无效请求。

  • 布隆过滤器:可以使用布隆过滤器在缓存之前检查数据是否存在,避免无效请求访问数据库。

Python实现布隆过滤器

import hashlib
import math

class BloomFilter:
    def __init__(self, capacity, error_rate):
        """
        初始化布隆过滤器
        :param capacity: 预计集合的最大容量
        :param error_rate: 允许的误判率 (比如 0.01 代表 1% 的误判率)
        """
        # 计算位数组的大小
        self.size = self._get_optimal_size(capacity, error_rate)
        
        # 计算哈希函数的个数
        self.hash_count = self._get_optimal_hash_count(self.size, capacity)
        
        # 初始化位数组,所有位为 0
        self.bit_array = [0] * self.size
    
    def _get_optimal_size(self, capacity, error_rate):
        """
        计算布隆过滤器的位数组大小
        :param capacity: 预计最大元素数量
        :param error_rate: 允许的误判率
        :return: 位数组的大小
        """
        # 计算位数组的大小
        return int(-(capacity * math.log(error_rate)) / (math.log(2) ** 2))
    
    def _get_optimal_hash_count(self, size, capacity):
        """
        计算哈希函数的个数
        :param size: 位数组的大小
        :param capacity: 预计最大元素数量
        :return: 哈希函数个数
        """
        return int((size / capacity) * math.log(2))
    
    def _hash(self, item, i):
        """
        根据元素和索引生成哈希值
        :param item: 待哈希的元素
        :param i: 哈希函数的索引
        :return: 哈希值
        """
        hash_obj = hashlib.md5((str(i) + item).encode('utf-8'))
        return int(hash_obj.hexdigest(), 16) % self.size
    
    def add(self, item):
        """
        向布隆过滤器中添加一个元素
        :param item: 待添加的元素
        """
        for i in range(self.hash_count):
            index = self._hash(item, i)
            self.bit_array[index] = 1
    
    def contains(self, item):
        """
        判断布隆过滤器中是否包含某个元素
        :param item: 待查询的元素
        :return: 如果包含返回 True, 否则返回 False
        """
        for i in range(self.hash_count):
            index = self._hash(item, i)
            if self.bit_array[index] == 0:
                return False
        return True

# 使用示例
if __name__ == '__main__':
    # 创建一个布隆过滤器,预计最多插入 10000 个元素,误判率为 1%
    bloom = BloomFilter(capacity=10000, error_rate=0.01)

    # 添加元素
    bloom.add("apple")
    bloom.add("banana")
    bloom.add("cherry")
    
    # 查询元素
    print(bloom.contains("apple"))   # 输出: True
    print(bloom.contains("banana"))  # 输出: True
    print(bloom.contains("grape"))   # 输出: False (可能为 False,若发生误判)

缓存击穿

定义:缓存击穿是指缓存中某个热点数据失效(过期或被清除),而有大量并发请求同时访问该数据,导致缓存失效后,所有请求都直接访问数据库,给数据库带来巨大的压力。

原因

  • 缓存数据失效,且没有及时更新。

  • 多个请求同时并发,导致数据库压力大,影响系统性能。

解决方案

  • 锁机制:可以使用互斥锁、分布式锁来保证同一时刻只有一个请求能查询数据库并更新缓存,避免多个请求并发访问数据库。

  • 提前预热缓存:设置热点数据永不过期,通过后台异步任务定时刷新数据。

缓存雪崩

定义:缓存雪崩是指缓存中大量数据同时失效,导致大量请求直接访问数据库,短时间内数据库负载急剧增加,可能导致数据库宕机或者性能大幅下降。

原因

  • 缓存中的大量数据过期时间相近,导致在同一时刻大量请求同时访问数据库。

  • 由于缓存失效而导致短时间内大量请求集中访问数据库,造成系统崩溃。

解决方案

  • 设置不同的缓存过期时间:通过设置不同的过期时间,避免大量数据同时过期。

  • 使用多级缓存:在不同层次(如本地缓存、分布式缓存)之间进行缓存的数据分布,降低单点缓存失效的影响。

布隆过滤器

布隆过滤器(Bloom Filter)是一种空间效率高、时间效率高的概率数据结构,用于测试一个元素是否属于一个集合。它可以在常数时间内进行查询和插入,但有一定的误判率(即可能会误报元素在集合中,但绝不会漏报)。

基本步骤:

  1. 初始化:设定位数组的大小和哈希函数的个数。

  2. 插入元素:通过哈希函数将元素映射到位数组的多个位置并设置为 1。

  3. 查询元素:通过哈希函数检查多个位置是否都是 1,如果有一个位置为 0,则说明元素不在集合中。

标签:缓存,capacity,self,击穿,param,雪崩,哈希,数据库
From: https://blog.csdn.net/fengjingping11/article/details/145169470

相关文章

  • MyBatis缓存原理及插件实现
    目录MyBatis缓存原理缓存的工作机制一级缓存:二级缓存:MyBatis插件实现MyBatis缓存原理缓存的工作机制如果会话查询了一条数据,此数据会存入一级缓存;若会话被关闭或提交,则,其数据转存入二级缓存;新会话若再次查询之前查询过的数据,就从二级缓存中获取;不同的Mapper,查询出......
  • MyBatis基于XML的详细使用-缓存
    MyBatis基于XML的详细使用-缓存1、介绍MyBatis内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。为了使它更加强大而且易于配置,我们对MyBatis3中的缓存实现进行了许多改进。默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。要启用......
  • Redis动态热点数据缓存策略设计
    Redis动态热点数据缓存策略设计1.热点数据识别机制1.1计数器方式@ServicepublicclassHotDataCounter{@AutowiredprivateRedisTemplate<String,Object>redisTemplate;//访问计数publicvoidincrementCounter(Stringkey){Strin......
  • vue3.0 keep-alive 缓存指定页面
    vue3.0keep-alive缓存指定页面**vue2.0和vue3.0keep-alive写法是有区别,不要太过于依赖AI**!!!!vue2的写法(不适用于vue3)<keep-alive><router-viewv-if="$route.meta.keepAlive"></router-view></keep-alive><router-viewv-if="!$route.met......
  • Caffeine 缓存 动态的为每个值设置过期时间
    引入jar<!--本地缓存caffeine--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency><dependency&......
  • 【前端】前端需要知道的缓存知识总结
    引言......
  • Redis 缓存穿透、击穿、雪崩——解析与防范
    前言Redis是一个高性能的键值数据库,广泛应用于缓存、会话存储、实时数据分析等场景。然而,在高并发的环境下,Redis缓存可能会遇到缓存击穿、缓存穿透和缓存雪崩这三大问题。这些问题不仅影响系统的稳定性和性能,还经常出现在面试题中,值得我们深入了解和防范......
  • 【Varnish】:解决 Varnish 7.6 CDN 静态资源缓存失效问题
    项目场景:在一个使用Varnish作为反向代理的Web应用中,我们依赖CDN(内容分发网络)来缓存静态资源(如图片、CSS、JavaScript文件等),以提高全球用户的访问速度并减轻源站服务器的负载。然而,在实际运行中,我们遇到了一个问题:CDN缓存的静态资源全部一直回源,导致源站服务器负载过高,响应时间......
  • Java内存与缓存
    Java内存管理和缓存机制是构建高性能应用程序的关键要素。它们之间既有联系又有区别,理解这两者对于优化Java应用至关重要。Java内存模型Java内存模型(JMM)定义了线程如何以及何时可以看到其他线程修改过的共享变量的值,并且规定了所有线程在读取或写入共享变量时必须遵循的一......
  • 缓存提速+队列削峰+分库分表+读写分离
    项目背景由于访问量超出设计预期,12306网站在高峰期出现了一系列问题:页面打开缓慢查询和下单报错后台系统过载用户体验不佳根因分析请求高峰(类似于秒杀)响应迟缓  放票时高并发的下单集中在一起,形成请求高峰(类似于秒杀),请求导致订单/电子客票数据......