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

高并发如何实现单用户信息查询接口

高并发如何实现单用户信息查询接口

故事情节

  • 产品:小李,有个单用户信息查询的功能,需要你实现一下
  • 小李:这还不简单,两分钟我给你实现
  • 两分钟过去…
  • 小李:欧克了,部署上线了
  • 运维:哪个傻蛋写的接口,导致MySQL宕机了
  • 小李一愣,他写的接口明明没有报错啊,这是怎么回事呢?
  • 产品:小李赶紧给我排查出来,否则这个月的奖金一分都没有
  • 小李:这这这,我不知道什么问题啊
  • 小李纳闷中,思来思去不知道什么问题如何解决…
  • 小李:老黄,只能求你出马了,这个月我的奖金全部都给你
  • 老黄听到小李的请求,他微微一笑,答应了下来
  • 老黄:么得问题了
  • 老黄耐心地指导小李修复了这个错误,并对代码进行了优化和完善
  • 小李听得认真,心里暗自发誓要吸取教训,以后在工作中更加严谨细致。而这次经历也让他对老黄产生了更深的敬意和信任
  • 最终,小李成功排查并解决了问题,产品顺利上线运行。产品部门的领导对他的表现给予了肯定和赞赏,而他也因为自己的努力和进步获得了全额的奖金

小李写的代码:

Service层:
直接查询MySQL返回数据

 public UserQueryRespDTO queryUserByUserId(Long userId) {LambdaQueryWrapper<UserDO> queryWrapper = Wrappers.lambdaQuery(UserDO.class).eq(UserDO::getUserId, userId);List<UserDO> userDOList = userMapper.selectList(queryWrapper);UserDO userDO = CollUtil.isNotEmpty(userDOList) ? userDOList.get(0) : null;UserQueryRespDTO userQueryRespDTO = new UserQueryRespDTO();BeanUtil.convert(userDO, userQueryRespDTO);return userQueryRespDTO;
}

流程图:
在这里插入图片描述

http 请求直接打到 MySQL 数据库,不宕机才怪嘞

老黄写的代码:

Service层:

  1. 先读取 Redis 缓存,数据存在直接返回用户
  2. 数据不存在,读取 MySQL 数据库,加上双重判定锁,减轻获得分布式锁后线程访问数据库压力
  3. 读取到 MySQL 数据,缓存到 Redis 并且返回
  4. 读取数据为NULL,缓存空对象到 Redis 中,并设置一个较短的过期时间(防止缓存穿透)
public UserQueryRespDTO queryUserByUserId(Long userId) {UserDO userDO = distributedCache.safeGet(USER_INFO_KEY + userId,UserDO.class,() -> {LambdaQueryWrapper<UserDO> queryWrapper = Wrappers.lambdaQuery(UserDO.class).eq(UserDO::getUserId, userId);List<UserDO> userDOList = userMapper.selectList(queryWrapper);return CollUtil.isNotEmpty(userDOList) ? userDOList.get(0) : null;},30,TimeUnit.MINUTES,null,null,key -> {// 缓存空对象,解决缓存穿透。也可以使用布隆过滤器。distributedCache.put(key, new UserDO(), 5, TimeUnit.MINUTES);});UserQueryRespDTO userQueryRespDTO = new UserQueryRespDTO();BeanUtil.convert(userDO, userQueryRespDTO);return userQueryRespDTO;
}

第二行distributedCache.safeGet方法

public <T> T safeGet(String key, Class<T> clazz, CacheLoader<T> cacheLoader, long timeout, TimeUnit timeUnit,RBloomFilter<String> bloomFilter, CacheGetFilter<String> cacheGetFilter, CacheGetIfAbsent<String> cacheGetIfAbsent) {T result = get(key, clazz);// 缓存结果不等于空或空字符串直接返回;通过函数判断是否返回空,为了适配布隆过滤器无法删除的场景;两者都不成立,判断布隆过滤器是否存在,不存在返回空if (!CacheUtil.isNullOrBlank(result)|| Optional.ofNullable(cacheGetFilter).map(each -> each.filter(key)).orElse(false)|| Optional.ofNullable(bloomFilter).map(each -> !each.contains(key)).orElse(false)) {return result;}RLock lock = redissonClient.getLock(SAFE_GET_DISTRIBUTED_LOCK_KEY_PREFIX + key);lock.lock();try {// 双重判定锁,减轻获得分布式锁后线程访问数据库压力if (CacheUtil.isNullOrBlank(result = get(key, clazz))) {// 如果访问 cacheLoader 加载数据为空,执行后置函数操作if (CacheUtil.isNullOrBlank(result = loadAndSet(key, cacheLoader, timeout, timeUnit, true, bloomFilter))) {Optional.ofNullable(cacheGetIfAbsent).ifPresent(each -> each.execute(key));}}} finally {lock.unlock();}return result;
}

流程图:
在这里插入图片描述

相关文章:

  • 现代C++ 实现单例模式
  • Windows 11上边两个空格导致我多熬了1个多小时
  • TOGAF—架构(Architecture)项目管理
  • npm ,yarn 更换使用国内镜像源,阿里源,清华大学源
  • Tomcat 十大安全优化方法(详解版)
  • 浅析LDPC软解码对SSD延迟的影响-part1
  • 浅入浅出理解MySQL和InnoDB
  • 安装python
  • 【PHP】openssl_encrypt、openssl_decrypt对称加密解密
  • 【ArcGIS微课1000例】0079:ArcGIS Earth根据经纬坐标生成点shapefile
  • 初识Pandas函数是Python的一个库(继续更新...)
  • 在Linux上配置全局HTTP代理的详细步骤
  • Parade Series - Message Interaction
  • 【数据结构】——查找、散列表简答题模板
  • 动态内存管理,malloc和calloc以及realloc函数用法
  • CSS选择器——伪元素选择器之处理父元素高度及外边距溢出
  • eclipse(luna)创建web工程
  • ECMAScript入门(七)--Module语法
  • fetch 从初识到应用
  • Java方法详解
  • js作用域和this的理解
  • Linux中的硬链接与软链接
  • maya建模与骨骼动画快速实现人工鱼
  • Sass 快速入门教程
  • Spring技术内幕笔记(2):Spring MVC 与 Web
  • WePY 在小程序性能调优上做出的探究
  • 如何用vue打造一个移动端音乐播放器
  • 扫描识别控件Dynamic Web TWAIN v12.2发布,改进SSL证书
  • 山寨一个 Promise
  • 使用阿里云发布分布式网站,开发时候应该注意什么?
  • 数据库写操作弃用“SELECT ... FOR UPDATE”解决方案
  • 掌握面试——弹出框的实现(一道题中包含布局/js设计模式)
  • 智能合约开发环境搭建及Hello World合约
  • 中文输入法与React文本输入框的问题与解决方案
  • NLPIR智能语义技术让大数据挖掘更简单
  • 仓管云——企业云erp功能有哪些?
  • 带你开发类似Pokemon Go的AR游戏
  • ​​​​​​​sokit v1.3抓手机应用socket数据包: Socket是传输控制层协议,WebSocket是应用层协议。
  • ​LeetCode解法汇总2808. 使循环数组所有元素相等的最少秒数
  • ​低代码平台的核心价值与优势
  • $(document).ready(function(){}), $().ready(function(){})和$(function(){})三者区别
  • (11)MATLAB PCA+SVM 人脸识别
  • (3)llvm ir转换过程
  • (4) openssl rsa/pkey(查看私钥、从私钥中提取公钥、查看公钥)
  • (C#)Windows Shell 外壳编程系列9 - QueryInfo 扩展提示
  • (C++20) consteval立即函数
  • (k8s中)docker netty OOM问题记录
  • (超详细)语音信号处理之特征提取
  • (二)基于wpr_simulation 的Ros机器人运动控制,gazebo仿真
  • (附源码)SSM环卫人员管理平台 计算机毕设36412
  • (四)TensorRT | 基于 GPU 端的 Python 推理
  • (转)Android学习笔记 --- android任务栈和启动模式
  • (转)setTimeout 和 setInterval 的区别
  • ***检测工具之RKHunter AIDE
  • .NET Conf 2023 回顾 – 庆祝社区、创新和 .NET 8 的发布