redis-缓存三剑客

news/2024/8/26 15:38:17 标签: 缓存, redis, 数据库

缓存穿透

定义

缓存穿透是指用户请求的数据既不在缓存中,也不在数据库中。每次这样的请求都会穿透缓存,直接访问数据库,增加数据库的负载。

原因
  • 恶意攻击:攻击者不断请求不存在的数据。
  • 无效请求:用户请求的数据在数据库中不存在。
解决办法

1.布隆过滤器预检查

布隆过滤器是一种高效的概率型数据结构,可以快速判断某个元素是否存在。它可以在缓存之前进行预检查,过滤掉那些不可能存在的数据请求。

public class BloomFilter {
    private BitSet bitSet;
    private int size;
    private int hashCount;

    public BloomFilter(int size, int hashCount) {
        this.size = size;
        this.hashCount = hashCount;
        this.bitSet = new BitSet(size);
    }

    private int hash(String item, int i) {
        int hash1 = item.hashCode();
        int hash2 = (hash1 >>> 16) ^ (hash1 << 1);
        return Math.abs((hash1 + i * hash2) % size);
    }

    public void add(String item) {
        for (int i = 0; i < hashCount; i++) {
            bitSet.set(hash(item, i));
        }
    }

    public boolean mightContain(String item) {
        for (int i = 0; i < hashCount; i++) {
            if (!bitSet.get(hash(item, i))) {
                return false;
            }
        }
        return true;
    }
}

 

2.缓存空结果

当查询数据库未命中时,可以将空结果缓存一段时间,避免短时间内重复查询数据库

public class CacheService {
    private static final Object NULL_OBJECT = new Object();
    private Map<String, Object> cache = new HashMap<>();

    public Object getData(String key) {
        Object data = cache.get(key);
        if (data == null) {
            data = queryDatabase(key);
            cache.put(key, data == null ? NULL_OBJECT : data);
        }
        return data == NULL_OBJECT ? null : data;
    }

    private Object queryDatabase(String key) {
        // 查询数据库逻辑
        return null;
    }
}

缓存击穿

定义

缓存击穿是指一个非常热门的key在缓存失效的时刻,同时有大量的并发请求到达,这些请求发现缓存失效后同时访问数据库,导致数据库压力骤增。

解决办法

1.互斥锁(Mutex)

缓存失效时,通过互斥锁确保只有一个请求可以查询数据库并更新缓存,其他请求需要等待缓存更新完成。

public class ProductService {
    private Map<String, Product> cache = new HashMap<>();
    private Object lock = new Object();

    public Product getProduct(String productId) {
        Product product = cache.get(productId);
        if (product == null) {
            synchronized (lock) {
                product = cache.get(productId);
                if (product == null) {
                    product = queryDatabase(productId);
                    cache.put(productId, product);
                }
            }
        }
        return product;
    }

    private Product queryDatabase(String productId) {
        // 查询数据库逻辑
        return new Product(productId, "Sample Product");
    }
}

 

2.设置热点数据永不过期

对热点数据不设置过期时间,保持缓存中的数据始终有效,避免缓存失效引发的并发访问数据库问题。

public class NewsService {
    private Map<String, Integer> cache = new HashMap<>();

    public int getClickCount(String newsId) {
        Integer clickCount = cache.get(newsId);
        if (clickCount == null) {
            clickCount = queryDatabase(newsId);
            cache.put(newsId, clickCount);
        }
        return clickCount;
    }

    private int queryDatabase(String newsId) {
        // 查询数据库逻辑
        return 100; // 示例数据
    }
}

缓存雪崩

定义

缓存雪崩是指在某一时间段内,大量缓存同时失效,导致大量请求直接访问数据库,引发数据库压力骤增,甚至导致系统崩溃。

解决办法

1.缓存过期时间分散

设置缓存时,给不同的缓存键设置随机的过期时间,避免大量缓存同时失效。

public void cacheData(String key, Object data) {
    int expiryTime = 3600 + new Random().nextInt(600); // 随机过期时间
    cache.put(key, data, expiryTime);
}

 

2.双层缓存

使用本地缓存和分布式缓存双层架构,本地缓存作为第一层,分布式缓存作为第二层,减少数据库直接访问的压力。

public class DoubleLayerCache {
    private Map<String, Object> localCache = new HashMap<>();
    private Map<String, Object> distributedCache = new HashMap<>();

    public Object getData(String key) {
        Object data = localCache.get(key);
        if (data == null) {
            data = distributedCache.get(key);
            if (data == null) {
                data = queryDatabase(key);
                distributedCache.put(key, data);
            }
            localCache.put(key, data);
        }
        return data;
    }

    private Object queryDatabase(String key) {
        // 查询数据库逻辑
        return "Sample Data"; // 示例数据
    }
}

3.请求限流

当检测到数据库压力过大时,对请求进行限流,或者降级处理,返回默认值或错误信息,保护数据库

public Object getDataWithRateLimit(String key) {
    if (rateLimiter.allowRequest()) {
        return getData(key);
    } else {
        return "Service is busy, please try again later.";
    }
}

总结

缓存穿透、缓存击穿和缓存雪崩是缓存系统中常见的问题。通过使用布隆过滤器、互斥锁、双层缓存等技术,可以有效防止这些问题的发生,确保系统的稳定性和高可用性。选择合适的解决方案,可以显著提高系统的性能和用户体验。希望这些详细的解释和代码示例能帮助你更好地理解和解决这些缓存问题。


http://www.niftyadmin.cn/n/5558197.html

相关文章

数据可视化在石油新能源行业的应用:深度探索与前沿趋势

引言 随着全球对能源需求的不断增长和环保意识的日益增强&#xff0c;石油新能源行业正面临着前所未有的挑战与机遇。在这个背景下&#xff0c;数据可视化技术以其直观、易懂、高效的特点&#xff0c;为石油新能源行业提供了强大的支持。本文将从数据可视化的基本概念出发&…

【源码阅读】osproxy对象存储分布式代理(2)--初始化底层服务和日志器

文章目录 初始化底层服务函数返回类型APPRedis newLangGoConfig()函数initLangGoConfig()函数 初始化日志器 上一章【源码阅读】osproxy对象存储分布式代理&#xff08;1&#xff09;下一章 这部分涉及了对于底层服务的初始化和日志器的初始化两部分 // 初始化底层服务&#x…

【Godot4.2】MLTag类:HTML、XML通用标签类

概述 HTML和XML采用类似的标签形式。 之前在Godot中以函数库形式实现了网页标签和内容生成。能用&#xff0c;但是缺点也很明显。函数之间没有从属关系&#xff0c;但是多有依赖&#xff0c;而且没有划分出各种对象和类型。 如果以完全的面向对象形式来设计标签类或者元素类…

vscode 打开远程bug vscode Failed to parse remote port from server output

vscode 打开远程bug vscode Failed to parse remote port from server output 原因如图&#xff1a; 解决&#xff1a;

llama-cpp-python

文章目录 一、关于 llama-cpp-python二、安装安装配置支持的后端Windows 笔记MacOS笔记升级和重新安装 三、高级API1、简单示例2、从 Hugging Face Hub 中提取模型3、聊天完成4、JSON和JSON模式JSON模式JSON Schema 模式 5、函数调用6、多模态模型7、Speculative Decoding8、Em…

webpack生产环境下的配置

css 处理 css提取 下载包 npm i -D mini-css-extract-plugin 配置 module: {rules: [{test: /\.css$/,use: [// style-loader, // 创建style标签&#xff0c;将样式加入js文件MiniCssExtractPlugin.loader, // 提取js中的css成单独的文件css-loader,]}, ]},plugins: [new H…

新书速览|深入理解Hive:从基础到高阶:视频教学版

《深入理解Hive&#xff1a;从基础到高阶&#xff1a;视频教学版》 本书内容 《深入理解Hive:从基础到高阶:视频教学版》采用“理论实战”的形式编写&#xff0c;通过大量的实例&#xff0c;结合作者多年一线开发实战经验&#xff0c;全面地介绍Hive的使用方法。《深入理解Hiv…

Spring与设计模式实战之策略模式

Spring与设计模式实战之策略模式 引言 在现代软件开发中&#xff0c;设计模式是解决常见设计问题的有效工具。它们提供了经过验证的解决方案&#xff0c;帮助开发人员构建灵活、可扩展和可维护的系统。本文将探讨策略模式在Spring框架中的应用&#xff0c;并通过实际例子展示…