redis同步解决 缓存击穿+缓存穿透 原理代码实现

devtools/2024/10/11 0:50:58/

缓存穿透

 就是一个根本不存在的数据 请求过来,然后 发现缓存没有,就打到数据库,然后 数据库也没有,就会给数据库造成很大的压力 ,

解决方案 就是老生常谈的  返回null值,或者布隆过滤器  

我们说 返回null值     也就是 在查到数据库之后,发现数据库没有,就缓存一个null值到缓存,然后 返回回去,这样下一个请求过来了,就会读到我们redis缓存的null值

缓存击穿

 一个热点 key 突然过期了,这时候有大量的请求突然访问过来,但是缓存过期了,请求直接打到数据库,造成数据库压力过大  

一般解决方案 有两种 

1. 用redis的互斥锁 ,保证缓存过期的时候,只有一个线程能访问数据库,然后 构建缓存,其他线程 用自旋锁一直挂起, 在挂起的时候,线程休眠一下,然后一直获取缓存 

2. 逻辑过期  原理很简单 既然缓存会过期,那你设置永不过期就行了,然后给类中添加 逻辑过期 时间,每次获得线程的时候 只要判断逻辑过期没有,逻辑过期了,就获取互斥锁,重建缓存

这样说 可能比较抽象 ,我们下面直接进行代码实现  ,保证解决缓存穿透的同时,再用互斥锁解决缓存击穿的问题

业务逻辑图

如果不理解,那就自己脑补一下多线程的情况

 下面是代码实现

获取锁的类

获得锁
 然后代码实现

根据id访问缓存

.

最后的逻辑实现
 //互斥锁解决缓存击穿private Result nXPassThrough(Long id) throws InterruptedException {Result shopMap = findShopMap(id);if (shopMap.getErrorMsg() == null) {return Result.ok(shopMap);}//解决缓存击穿//走到这里  代表着 缓存查不到了//1. 获取 redisson 互斥锁//2. 获取不成功 自旋等待while (true) {if (passThroughLock.tryLock()) {try {log.info("获得到了锁");//2. 获取成功查询数据库 返回缓存数据//没有的话查数据库Shop shopById = query().eq("id", id).one();if (BeanUtil.isNotEmpty(shopById)) {//数据库有的话 添加缓存并且返回Result shopMap1 = findShopMap(id);if (shopMap1.getErrorMsg() == null) {return Result.ok(shopMap1);}Map<String, Object> stringObjectMap = BeanUtil.beanToMap(shopById);redisTemplate.opsForHash().putAll(RedisConstants.CACHE_SHOP_KEY + id, stringObjectMap);// 设置过期时间 防止内存 占满redisTemplate.expire(RedisConstants.CACHE_SHOP_KEY + id, RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);return Result.ok(shopById);}//数据库没有 返回false//解决缓存穿透   访问不存在的数据 缓存为null值 并且设置过期时间log.info("缓存穿透 构建了新数据");redisTemplate.opsForHash().put(RedisConstants.CACHE_SHOP_KEY + id, "nullId", "null");redisTemplate.expire(RedisConstants.CACHE_SHOP_KEY + id, RedisConstants.CACHE_NULL_TTL, TimeUnit.SECONDS);return Result.ok("返回成功");} finally {passThroughLock.unlock();}} else {try {Thread.sleep(100);Result shopMap1 = findShopMap(id);if (shopMap1.getErrorMsg() == null) {return Result.ok(shopMap1);}} catch (InterruptedException e) {return Result.fail(e.getMessage());}}}}
jmter压测结果

当我们访问数据库存在的数据

当我们访问数据库不存在的数据

也是同样的情况只查询到了一次sql,并且构建了新的空数据


http://www.ppmy.cn/devtools/123907.html

相关文章

基于floor函数报错注入sqli-labs less-5和less-6

sqli-labs第五六关基于floor报错注入 测试基于虚拟机搭建的靶场&#xff0c;在主机浏览器进行测试 首先能到第五关的对于基础的字符数字型判断&#xff0c;闭合方式&#xff0c;列数判断有一定了解&#xff0c;所以不再进行演示&#xff0c;直接进行数据爆破 关于floor函数报错…

2024互联网下载神器IDM6.42你值得拥有

&#x1f525; 互联网下载神器大揭秘&#xff01;IDM6.42你值得拥有 &#x1f680; Hey&#xff0c;各位小伙伴们&#xff0c;今天我要给你们安利一款我超爱的软件——Internet Download Manager 6.42&#xff08;简称IDM&#xff09;&#xff0c;这款下载器简直就是下载界的“…

Jensen-Shannon散度(JS散度)

Jensen-Shannon散度&#xff08;Jensen-Shannon Divergence, JS散度&#xff09;是概率分布之间的一种相似性度量。它是基于Kullback-Leibler散度&#xff08;KL散度&#xff09;的对称版本&#xff0c;并且具有一些更好的性质&#xff0c;例如它总是非负的&#xff0c;并且是有…

【笔记学习篇】一篇文章搞定Mybatis-快速回顾

概述 5.1.1 Mybatis简介 Mybatis是一款优秀的持久层框架&#xff0c;它以sql为中心&#xff0c;支持定制化sql、存储过程以及高级映射。 使用Mybatis框架&#xff0c;可以无需手动编写基础的JDBC代码、无需手动设置参数和转换结果集到对象。 Mybatis可以使用简单的xml或注解来…

java速成指南

密码都是 123 适用于php .net 7天转java 【腾讯文档】快速上手培训-阿龙 分享给你多个文件 https://docs.qq.com/s/jUcRQ4VPA4grzx8SPYzrBa 第一节 安装jdk,maven,idea_哔哩哔哩_bilibili

心觉:开发潜意识的详细流程和步骤是什么

Hi&#xff0c;我是心觉&#xff0c;与你一起玩转潜意识、脑波音乐和吸引力法则&#xff0c;轻松掌控自己的人生&#xff01; 挑战每日一省写作195/1000天 最近领教了一下潜意识的力量和吸引力法则 我想要一张可以放在榻榻米壁柜上的迷你型的电动升降桌&#xff0c;桌面60cm…

网络编程(17)——asio多线程模型IOThreadPool

十七、day17 之前我们介绍了IOServicePool的方式&#xff0c;一个IOServicePool开启n个线程和n个iocontext&#xff0c;每个线程内独立运行iocontext, 各个iocontext监听各自绑定的socket是否就绪&#xff0c;如果就绪就在各自线程里触发回调函数。为避免线程安全问题&#xf…

Python测试框架--Allure

严格意义上讲 Allure 不算是测试框架&#xff0c;但是它是生成漂亮测试报告的开源工具&#xff0c;搭配 Pytest 测试框架食用更搭。 也就是说 Allure 是在 Pytest 执行完生成的测试数据的基础上&#xff0c;对测试数据进行处理统计&#xff0c;生成格式统一、美观的测试报告。 …