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

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.";}
}

总结

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

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • FreeRTOS的中断管理、临界资源保护、任务调度
  • 2024CAIP省赛
  • 【吊打面试官系列-ZooKeeper面试题】简述 Zookeeper 文件系统?
  • 安全运营概述
  • 【学习】美国虚拟信用卡申请流程
  • 【解决】多个网卡导致nacos注册的服务ip有误问题
  • Java-排序~查找算法
  • Qt会议室项目
  • 景区导航导览系统:基于AR技术+VR技术的功能效益全面解析
  • RocketMQ实现分布式事务
  • vst 算法R语言手工实现 | Seurat 筛选高变基因的算法
  • 优化Python爬虫:多线程助力数据采集高速通道
  • vue仿甘特图开发工程施工进度表
  • openeuler 终端中文显示乱码、linux vim中文乱码
  • Billu_b0x靶机
  • canvas绘制圆角头像
  • CSS3 聊天气泡框以及 inherit、currentColor 关键字
  • golang 发送GET和POST示例
  • HashMap剖析之内部结构
  • js写一个简单的选项卡
  • MD5加密原理解析及OC版原理实现
  • MyEclipse 8.0 GA 搭建 Struts2 + Spring2 + Hibernate3 (测试)
  • mysql常用命令汇总
  • Node + FFmpeg 实现Canvas动画导出视频
  • PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql
  • Rancher如何对接Ceph-RBD块存储
  • vue-cli在webpack的配置文件探究
  • 搭建gitbook 和 访问权限认证
  • 浮现式设计
  • 官方解决所有 npm 全局安装权限问题
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 回顾 Swift 多平台移植进度 #2
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 基于遗传算法的优化问题求解
  • 京东美团研发面经
  • 使用agvtool更改app version/build
  • 适配mpvue平台的的微信小程序日历组件mpvue-calendar
  • 数据科学 第 3 章 11 字符串处理
  • 微信公众号开发小记——5.python微信红包
  • 为物联网而生:高性能时间序列数据库HiTSDB商业化首发!
  • 线性表及其算法(java实现)
  • ionic异常记录
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • 智能情侣枕Pillow Talk,倾听彼此的心跳
  • # 安徽锐锋科技IDMS系统简介
  • #define、const、typedef的差别
  • #pragma预处理命令
  • $.proxy和$.extend
  • $forceUpdate()函数
  • (17)Hive ——MR任务的map与reduce个数由什么决定?
  • (附源码)springboot炼糖厂地磅全自动控制系统 毕业设计 341357
  • (附源码)springboot太原学院贫困生申请管理系统 毕业设计 101517
  • (汇总)os模块以及shutil模块对文件的操作
  • (七)Appdesigner-初步入门及常用组件的使用方法说明
  • (全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF