高并发下redis缓存穿透问题解决方案
一、使用场景
我们在日常的开发中,经常会遇到查询数据列表的问题,有些数据是不经常变化的,如果想做一下优化,在提高查询的速度的同时减轻数据库的压力,那么redis缓存绝对是一个好的解决方案。
二、需求
假设有10000个请求,想达到第一次请求从数据库中获取,其他9999个请求从redis中获取这种效果。
三、代码实现
3.1、常规写法
public List<UsersDO> getAllUserWithNoPage2(){try{//序列化器,将key的值设置为字符串RedisSerializer redisSerializer=new StringRedisSerializer();redisTemplate.setKeySerializer(redisSerializer);//查缓存List<UsersDO> list=(List<UsersDO>)redisTemplate.opsForValue().get("allUsers");if(null==list){UsersQuery query=new UsersQuery();list=usersDOMapper.selectByExample(query);redisTemplate.opsForValue().set("allUsers", list);System.out.println("从数据库中取数据");}else{System.out.println("从缓存中取数据");}return list;}catch (Exception e) {logger.error("UserService.getAllUserWithNoPage error",e);}return null;}
常规的这种写法单线程没有问题,但是考虑到并发的存在,就会出现缓存渗透的问题,也就是不能保证其他9999个请求都是从redis中取。
3.2、常规写法压测
@GetMapping(value = "/test2")public String test2(){ExecutorService executorService= Executors.newFixedThreadPool(20);for(int i=1 ; i<=10000;i++){executorService.submit(new Runnable() {@Overridepublic void run() {userService.getAllUserWithNoPage2();}});}return "test over";}
3.3、常规写法压测结果
3.4、常规写法的改进,使用双重检测锁
public List<UsersDO> getAllUserWithNoPage(){try{//序列化器,将key的值设置为字符串RedisSerializer redisSerializer=new StringRedisSerializer();redisTemplate.setKeySerializer(redisSerializer);//查缓存List<UsersDO> list=(List<UsersDO>)redisTemplate.opsForValue().get("allUsers");if(null==list){//双重检测 锁synchronized (this) {List<UsersDO> list1 = (List<UsersDO>) redisTemplate.opsForValue().get("allUsers");if (null == list1) {UsersQuery query=new UsersQuery();list=usersDOMapper.selectByExample(query);redisTemplate.opsForValue().set("allUsers", list);System.out.println("从数据库中取数据");}else{System.out.println("从缓存中取数据");}}}else{System.out.println("从缓存中取数据");}return list;}catch (Exception e) {logger.error("UserService.getAllUserWithNoPage error",e);}return null;}
3.5、双重检测锁压测
@GetMapping(value = "/test")public String test(){ExecutorService executorService= Executors.newFixedThreadPool(20);for(int i=1 ; i<=10000;i++){executorService.submit(new Runnable() {@Overridepublic void run() {userService.getAllUserWithNoPage();}});}return "test over";}
3.6、双重检测锁压测结果
压测结果符合要求。
完整代码已上传Github :传送门
转载于:https://www.cnblogs.com/geekdc/p/9256515.html
高并发下redis缓存穿透问题解决方案相关推荐
- 【redis】redis缓存穿透及解决方案|缓存穿透,缓存击穿,雪崩的理解
|目录 缓存穿透 解决方案 布隆过滤 缓存空对象 缓存雪崩 解决方案 1.保证缓存层服务高可用性 2.依赖隔离组件为后端限流并降级 3.数据预热 4.做二级缓存,或者双缓存策略. 5.缓存永远不过期 ...
- Redis缓存穿透与解决方案
什么是缓存穿透? 要查询的key在redis中不存在,对应的id(对应的值)在数据库中也不存在,此时被非法用户攻击,大量的请求直接打到db上,造成db宕机,从而影响整个系统.这就种现象就称之为缓存穿透 ...
- Redis缓存穿透、击穿、雪崩及主从复制
文章目录 Redis缓存穿透 概念 解决方案1-布隆过滤器 解决方案2-缓存空对象 缓存击穿 概念 解决方案1-热点数据永不过期 解决方案2-加互斥锁 缓存雪崩 概念 解决方案1-Redis高可用 解 ...
- Redis 缓存穿透、缓存击穿和缓存雪崩
目录 Redis 缓存穿透.缓存击穿和缓存雪崩 Redis 缓存穿透(查不到) Redis缓存穿透的解决方案 方案一:接口校验 方案二:缓存空对象 方案三:布隆过滤器 Redis 缓存击穿 Redis ...
- Redis缓存穿透,缓存击穿,缓存雪崩原因以及解决方案
一.前言 在我们日常的开发中,无不都是使用数据库来进行数据的存储,由于一般的系统任务中通常不会存在高并发的情况,所以这样看起来并没有什么问题,可是一旦涉及大数据量的需求,比如一些商品抢购的情景,或者是 ...
- Redis缓存穿透 缓存击穿 缓存雪崩原因及其解决方案
解决缓存穿透 方法一:布隆过滤器:将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力. 方法二:如果一个查询返回 ...
- redis缓存穿透问题及解决方案代码实现
1.定义及解决方案 缓存穿透 :缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库. 常见的解决方案有两种: 缓存空对象 优点:实现简单,维护方便 缺 ...
- Redis缓存穿透问题及解决方案
Redis缓存穿透问题及解决方案 参考文章: (1)Redis缓存穿透问题及解决方案 (2)https://www.cnblogs.com/lingyejun/p/10087135.html 备忘一下 ...
- redis缓存穿透,缓存击穿,缓存雪崩原因和解决方案
redis缓存穿透,缓存击穿,缓存雪崩原因和解决方案 参考文章: (1)redis缓存穿透,缓存击穿,缓存雪崩原因和解决方案 (2)https://www.cnblogs.com/shisuiliun ...
最新文章
- Android NDK开发之旅31 FFmpeg音频解码
- C#获取当前日期时间(转)
- Node.js 目录操作
- python包括哪些部分_python基础知识部分练习大全
- 【STM32】 keil新建工程模板
- IDEA新建maven项目漏掉webapp目录解决方法
- VMware虚拟机下安装Ubuntu16.04镜像完整教程
- tab vue 竖排_vue 实现tab切换保持数据状态
- c 连接mysql数据库_C++连接mysql数据库的两种方法
- android酷狗音乐播放器,酷狗音乐app官方下载
- php hprose扩展1.5.5,Laravel框架RPC解决方案--Hprose
- (分层图)洛谷P4568[JLOI2011]飞行路线
- 华为USG防火墙恢复密码步骤
- java epics_Visual Paradigm敏捷开发教程(7):如何管理Epics
- ERP“创建会计科目”的请求数据量过大报黄
- ArcGIS API for JavaScript 图层顺序
- matlab 蒙特卡罗计算pi值
- 如何部署超级签名分发平台系统?
- win10 C语言开发环境搭建
- Jmeter+InfluxDB+Grafana+Prometheus搭建遇过的问题
热门文章
- 科研找到属于自己的思想
- 远控软件VNC***案例研究
- smartbits的国产版本minismb-如何测试路由器
- SpringBoot系列三:SpringBoot基本概念(统一父 pom 管理、SpringBoot 代码测试、启动注解分析、配置访问路径、使用内置对象、项目打包发布)...
- KVM虚拟机添加虚拟磁盘
- Navicat Essentials 功能简介
- Innosetup(pascal)标签控件label换行
- Gson.toJson()时内存溢出StackOverflowError
- 2、程序包 Packages
- C#实现动态桌面背景图片切换