当前位置: 首页 > news >正文

防止缓存穿透

防止缓存穿透的完整方案详解

您提到的两种方法的完善与补充

方法一:布隆过滤器(您说的"两次哈希")

原理详解:
布隆过滤器使用多个哈希函数和一个位数组,通过"一定不存在"的特性来防止缓存穿透。

C++项目中的实际应用:

cpp

// 伪代码示例
class BloomFilterCacheService {
private:BloomFilter bloomFilter;      // 布隆过滤器RedisClient redis;           // Redis客户端Database db;                 // 数据库客户端public:std::string getData(const std::string& key) {// 1. 布隆过滤器检查if (!bloomFilter.mightContain(key)) {log("布隆过滤器拦截: " + key);return "";  // 一定不存在,直接返回}// 2. 查询Redisauto value = redis.get(key);if (value.has_value()) {return value.value();}// 3. 查询数据库value = db.query(key);if (value.has_value()) {// 写入Redis,设置合理过期时间redis.setex(key, 3600, value.value());return value.value();} else {// 数据库也不存在,可能是布隆过滤器误判log("布隆过滤器误判: " + key);return "";}}// 系统启动时预热布隆过滤器void warmUp() {auto allKeys = db.getAllExistingKeys();for (const auto& key : allKeys) {bloomFilter.add(key);}}
};

实际项目注意事项:

  • 布隆过滤器需要预热,系统启动时从数据库加载所有存在的key

  • 误判率需要根据业务需求调整(通常1%-3%)

  • 数据更新时需要同步更新布隆过滤器

  • 适合读多写少的场景

方法二:缓存空对象

原理详解:
将查询不到的结果也缓存起来,设置较短的过期时间,避免重复查询数据库。

C++项目中的实际应用:

cpp

class NullObjectCacheService {
private:RedisClient redis;Database db;const std::string NULL_VALUE = "##NULL##";const int NULL_TTL = 600; // 10分钟public:std::optional<std::string> getData(const std::string& key) {// 1. 查询Redisauto value = redis.get(key);if (value.has_value()) {if (value.value() == NULL_VALUE) {log("命中空对象缓存: " + key);return std::nullopt;  // 返回空,表示数据不存在}return value;}// 2. 查询数据库value = db.query(key);if (value.has_value()) {// 数据存在,正常缓存redis.setex(key, 3600, value.value());return value;} else {// 数据不存在,缓存空对象redis.setex(key, NULL_TTL, NULL_VALUE);log("缓存空对象: " + key);return std::nullopt;}}// 数据更新时清理空对象缓存void updateData(const std::string& key, const std::string& newValue) {db.update(key, newValue);// 如果之前缓存了空对象,需要清理auto cached = redis.get(key);if (cached.has_value() && cached.value() == NULL_VALUE) {redis.del(key);}// 更新缓存redis.setex(key, 3600, newValue);}
};

实际项目注意事项:

  • 空对象的TTL不宜过长,避免数据更新后的不一致

  • 需要监控空对象缓存的数量,防止内存耗尽

  • 数据更新时需要清理对应的空对象缓存

  • 可以使用随机TTL避免大量空对象同时过期

其他防止缓存穿透的方法

方法三:互斥锁方案

原理:
对同一个key的查询加锁,确保只有一个请求会查询数据库,其他请求等待并使用缓存结果。

C++实现思路:

cpp

class MutexLockCacheService {
private:std::shared_mutex global_mutex;std::unordered_map<std::string, std::shared_mutex> key_mutexes;std::mutex map_mutex;public:std::string getData(const std::string& key) {// 获取该key专用的互斥锁std::shared_mutex& key_mutex = getKeyMutex(key);// 先尝试共享锁读取{std::shared_lock read_lock(key_mutex);auto cached = redis.get(key);if (cached.has_value()) {return cached.value();}}// 获取独占锁进行数据库查询std::unique_lock write_lock(key_mutex);// 双重检查,防止其他线程已经写入auto cached = redis.get(key);if (cached.has_value()) {return cached.value();}// 查询数据库并写入缓存auto value = db.query(key);if (value.has_value()) {redis.setex(key, 3600, value.value());return value.value();} else {// 缓存空对象redis.setex(key, 600, "##NULL##");return "";}}
};

适用场景:

  • 高并发查询同一个不存在的key

  • 对数据一致性要求较高的场景

方法四:限流与熔断机制

原理:
对数据库查询进行限流,当异常查询过多时启动熔断,直接返回默认值。

C++实现思路:

cpp

class RateLimitCacheService {
private:std::atomic<int> request_count{0};std::atomic<int> fail_count{0};std::chrono::steady_clock::time_point window_start;const int MAX_REQUESTS = 1000;     // 每分钟最大请求数const int MAX_FAILS = 50;          // 熔断阈值public:std::string getData(const std::string& key) {// 检查限流if (!checkRateLimit()) {log("限流拦截: " + key);return getDefaultValue(key);}// 检查熔断if (isCircuitOpen()) {log("熔断拦截: " + key);return getDefaultValue(key);}// 正常查询流程auto value = redis.get(key);if (!value.has_value()) {value = db.query(key);if (!value.has_value()) {fail_count++;}}return value.value_or("");}
};

适用场景:

  • 突发大量恶意请求

  • 数据库压力过大时的保护机制

方法五:缓存预热与预加载

原理:
提前将可能被访问的数据加载到缓存中,包括已知的不存在数据。

C++实现思路:

cpp

class PreloadCacheService {
private:std::unordered_set<std::string> hot_key_patterns;public:void preloadData() {// 预加载热点数据auto hotKeys = predictHotKeys();for (const auto& key : hotKeys) {auto value = db.query(key);if (value.has_value()) {redis.setex(key, 7200, value.value()); // 热点数据缓存2小时} else {redis.setex(key, 1800, "##NULL##");    // 热点空数据缓存30分钟}}}// 基于历史数据预测热点keystd::vector<std::string> predictHotKeys() {// 从日志分析、业务规则等获取return {"user_123", "product_456", "config_global"};}
};

适用场景:

  • 已知的热点数据模式

  • 系统启动或定时任务

方法六:业务层校验

原理:
在业务逻辑层对请求参数进行校验,过滤明显不合法的请求。

C++实现思路:

cpp

class BusinessValidationService {
public:bool isValidRequest(const std::string& key) {// 1. 格式校验if (!isValidFormat(key)) {return false;}// 2. 范围校验if (!isInValidRange(key)) {return false;}// 3. 频率校验if (isTooFrequent(key)) {return false;}return true;}private:bool isValidFormat(const std::string& key) {// 检查key格式是否符合预期// 例如:用户ID应该是数字,商品ID应该符合特定格式等return std::regex_match(key, std::regex("^[a-zA-Z0-9_]+$"));}bool isInValidRange(const std::string& key) {// 检查key是否在合理范围内// 例如:用户ID应该在1-1000000之间return true;}
};

实际C++项目中的综合方案

在实际项目中,通常会组合使用多种方案:

cpp

class ComprehensiveCacheService {
private:BloomFilter bloomFilter;NullObjectCacheService nullCache;RateLimitCacheService rateLimit;BusinessValidationService validator;public:void init() {// 系统启动时初始化bloomFilter.warmUp();rateLimit.reset();}std::string getData(const std::string& key) {// 1. 业务层校验if (!validator.isValidRequest(key)) {log("业务校验失败: " + key);return "";}// 2. 限流检查if (rateLimit.shouldLimit()) {return getDefaultValue();}// 3. 布隆过滤器检查if (!bloomFilter.mightContain(key)) {return "";}// 4. 查询缓存(包含空对象)auto result = nullCache.getData(key);if (result.has_value()) {return result.value();}// 5. 如果以上都通过,说明是正常请求,可以记录日志等log("正常数据请求: " + key);return "";}
};

各种方法的优缺点对比

方法优点缺点适用场景
布隆过滤器内存效率高,拦截准确有误判率,需要预热大规模数据,读多写少
空对象缓存实现简单,效果直接内存消耗,数据不一致中小规模,key有限
互斥锁保证一致性,避免重复查询性能开销,复杂度高高并发单一key
限流熔断保护后端,系统稳定可能影响正常请求突发流量,系统保护
缓存预热提升性能,用户体验好需要预测,资源消耗已知热点数据
业务校验提前拦截,资源消耗小依赖业务规则所有场景

实际项目建议

  1. 基础方案:布隆过滤器 + 空对象缓存

  2. 增强方案:基础方案 + 限流熔断

  3. 完整方案:增强方案 + 业务校验 + 缓存预热

监控指标:

  • 缓存命中率

  • 数据库查询QPS

  • 布隆过滤器误判率

  • 空对象缓存数量

调优参数:

  • 布隆过滤器的容量和误判率

  • 空对象的TTL时间

  • 限流阈值和熔断条件

在实际C++项目中,根据业务特点和系统规模选择合适的方案组合,才能达到最佳的防缓存穿透效果。

http://www.dtcms.com/a/574585.html

相关文章:

  • 防火墙培训
  • 李宏毅机器学习笔记40
  • 网站开发甲方需求文档华为手机网络营销方式
  • 许昌旅游网站建设现状室内设计师联盟网站
  • 做公众号排版的网站常见的网络营销形式有哪些
  • AXI总线专题-AXI转SPI(接口)
  • 甘肃兴华建设集团网站怎么搭建一个视频网站
  • 珠海手机网站建设公司wordpress 数据库 备份
  • wordpress可以卸载360网站seo手机优化软件
  • 南山区住房和建设局网站莱芜都市网二手车租车
  • 中国建设银行网站查询密码是什么意思网站子页面怎么做的
  • 企业手机网站建设方案怎么自己建设一个网站
  • 集群网络技术2:流量控制与拥塞管理PFC ECN/DCQCN
  • 制作类网站哪里做网络推广
  • Spring Boot中使用Quartz实现动态定时任务
  • 2.4 python装饰器在 Web 框架和测试中的实战应用
  • 从容器化到自动化:Spring Boot 项目 Docker 部署与 GitLab CI/CD 集成 Harbor 全流程
  • 基于springboot的web的音乐网站开发与设计
  • AIIData数据中台商业版+开源版双模式
  • 音画同步革命:IndexTTS2深度解析——B站开源的情感化+时长可控TTS新标杆
  • 如果做淘宝网站wordpress 七牛视频播放
  • 成都模版网站制作网站建设项目结构分析
  • Transformer原理与过程详解
  • 迷你主机做网站c语言开发网站
  • 水利建设相关网站百度手机版下载
  • Nestjs框架: 微服务注册中心架构设计与Consul实战
  • 给别人网站做跳转网络公司排名中国
  • Apollo Monitor模块技术深度解析
  • 济南市建设银行网站温州城乡建设学校
  • 广告联盟没有网站怎么做商城网站建设公司排名