异步查询转同步加redis业务实现的BUG分享
在最近的性能测试中,某一个查询接口指标不通过,开发做了N次优化,最终的优化方案如下:异步查询然后转同步,再加上redis缓存。此为背景。
在测试过程中发现一个BUG:同样的请求在第一次查询结果是OK的,但是第二次查询(理论上讲得到的缓存数据)缺失了某些字段。
后端服务的测试代码如下,代码内容作了简化,留下了关键的部分,doSomething(dataMap);为简化方法,其中teacherPadAsyncService.doExcuteLikeSateAsync()、teacherPadAsyncService.doExcuteAccuracyAsync()、teacherPadAsyncService.doExcuteTeacherTagAsync这三个是异步方法:
@Override
public void doExecute(Map<String, Object> dataMap) {
String cache = defaultRedisUtil.getString(RedisKeyConfig.COURSE_PKG_DETAIL_KEY + id);
if (StringUtils.isNotBlank(cache)) {
dataMap = JSON.parseObject(cache, Map.class);
return;
}
doSomething(dataMap);
CountDownLatch countDownLatch = new CountDownLatch(3);
String traceKey = TraceKeyHolder.getTraceKey();
teacherPadAsyncService.doExcuteLikeSateAsync(dataMap, coursePackage.getId(),ResourceTypeEnum.COURSE_PACKAGE.value, currentUser.getSystemId(), countDownLatch, traceKey);
teacherPadAsyncService.doExcuteAccuracyAsync(dataMap, coursePackage.getId(), countDownLatch, traceKey);
teacherPadAsyncService.doExcuteTeacherTagAsync(dataMap, coursePackage, countDownLatch, traceKey);
doSomething(dataMap);
defaultRedisUtil.setString(RedisKeyConfig.COURSE_PKG_DETAIL_KEY + id, JSON.toJSONString(dataMap), RedisKeyConfig.COURSE_PKG_DETAIL_EXPIRE_TIME);
try {
countDownLatch.await();
} catch (InterruptedException e) {
logger.error("异步处理线程异常", e);
}
}
teacherPadAsyncService.doExcuteLikeSateAsync()这个方法是异步查询点赞状态,会在dataMap里面添加一个字段state,但是在第二次请求的时候有可能发现这个字段缺失,这只是其中一个BUG。原因在于往redis里面放置信息的时机不对,大概是由于写代码太着急,正确的做法应该是在异步转同步以后再去操作redis。下面是改之后的代码:
@Override
public void doExecute(Map<String, Object> dataMap) {
String cache = defaultRedisUtil.getString(RedisKeyConfig.COURSE_PKG_DETAIL_KEY + id);
if (StringUtils.isNotBlank(cache)) {
dataMap = JSON.parseObject(cache, Map.class);
return;
}
doSomething(dataMap);
CountDownLatch countDownLatch = new CountDownLatch(3);
String traceKey = TraceKeyHolder.getTraceKey();
teacherPadAsyncService.doExcuteLikeSateAsync(dataMap, coursePackage.getId(),ResourceTypeEnum.COURSE_PACKAGE.value, currentUser.getSystemId(), countDownLatch, traceKey);
teacherPadAsyncService.doExcuteAccuracyAsync(dataMap, coursePackage.getId(), countDownLatch, traceKey);
teacherPadAsyncService.doExcuteTeacherTagAsync(dataMap, coursePackage, countDownLatch, traceKey);
doSomething(dataMap);
try {
countDownLatch.await();
defaultRedisUtil.setString(RedisKeyConfig.COURSE_PKG_DETAIL_KEY + id, JSON.toJSONString(dataMap), RedisKeyConfig.COURSE_PKG_DETAIL_EXPIRE_TIME);
} catch (InterruptedException e) {
logger.error("异步处理线程异常", e);
}
}
BUG的原因也比较简单,由于第一次查询的时候redis里面内容时空的,所以走了数据库查询,查询到结果后,放到redis里面,但是在存redis时候,异步的查询任务并没有完成,导致第一次请求得多的响应是对的,但是redis里面存放的却是错误的。在缓存有效期内,查询的结果都将是错误的。
当然这个实现方法的BUG不止这一个,这里不列举了,有机会再分享。
- 郑重声明:文章首发于公众号“FunTester”,禁止第三方(腾讯云除外)转载、发表。
技术类文章精选
- java一行代码打印心形
- Linux性能监控软件netdata中文汉化版
- 性能测试框架第二版
- 如何在Linux命令行界面愉快进行性能测试
- 图解HTTP脑图
- 将swagger文档自动变成测试代码
- 基于java的直线型接口测试框架初探
- Selenium 4.0 Alpha更新日志
- Selenium 4.0 Alpha更新实践
- 如何统一接口测试的功能、自动化和性能测试用例
非技术文章精选
- 为什么选择软件测试作为职业道路?
- 写给所有人的编程思维
- 成为自动化测试的7种技能
- 如何在DevOps引入自动化测试
- Web端自动化测试失败原因汇总
- 如何在DevOps引入自动化测试
- 测试人员常用借口
- API测试基础
- API自动化测试指南
- 未来的QA测试工程师
异步查询转同步加redis业务实现的BUG分享的更多相关文章
- java 异步查询转同步多种实现方式:循环等待,CountDownLatch,Spring EventListener,超时处理和空循环性能优化
异步转同步 业务需求 有些接口查询反馈结果是异步返回的,无法立刻获取查询结果. 正常处理逻辑 触发异步操作,然后传递一个唯一标识. 等到异步结果返回,根据传入的唯一标识,匹配此次结果. 如何转换为同步 ...
- javascript 同步加载与异步加载
HTML 4.01 的script属性 charset: 可选.指定src引入代码的字符集,大多数浏览器忽略该值. defer: boolean, 可选.延迟脚本执行,相当于将script标签放入页面 ...
- Javascript 文件的同步加载与异步加载
HTML 4.01 的script属性 charset: 可选.指定src引入代码的字符集,大多数浏览器忽略该值.defer: boolean, 可选.延迟脚本执行,相当于将script标签放入页面b ...
- js 异步加载和同步加载
异步加载 异步加载也叫非阻塞模式加载,浏览器在下载js的同时,同时还会执行后续的页面处理.在script标签内,用js创建一个script元素并插入到document中,这种就是异步加载js文件了: ...
- 关于requireJS的同步加载和异步加载
这篇随笔主要记录require('name')和require(['name1','name2'])在同步和异步加载使用的区别 1.require('name')同步加载模块的形式 define(fu ...
- AJAX中的同步加载与异步加载
AJAX是四个单词的简写,其中Asynchronous即异步的意思,异步的链接可以同时发起多个,并且不会阻止JS代码执行.与之对应的概念是同步,同步的链接在同一时刻只会有一个,并且会阻止后续JS代码的 ...
- 【UE4 C++ 基础知识】<11>资源的同步加载与异步加载
同步加载 同步加载会造成进程阻塞. FObjectFinder / FClassFinder 在构造函数加载 ConstructorHelpers::FObjectFinder Constructor ...
- Redis和MySQL数据同步及Redis使用场景
1.同步MySQL数据到Redis (1) 在redis数据库设置缓存时间,当该条数据缓存时间过期之后自动释放,去数据库进行重新查询,但这样的话,我们放在缓存中的数据对数据的一致性要求不是很高才能放入 ...
- Net4.6 Task 异步函数 比 同步函数 慢5倍 踩坑经历
Net4.6 Task 异步函数 比 同步函数 慢5倍 踩坑经历 https://www.cnblogs.com/shuxiaolong/p/DotNet_Task_BUG.html 异步Task简单 ...
随机推荐
- CodeForces - 1189 E.Count Pairs (数学)
You are given a prime number pp, nn integers a1,a2,…,ana1,a2,…,an, and an integer kk. Find the numbe ...
- Kafka Eagle安装详情及问题解答
1.概述 最近有很多同学给笔者留言,说在安装Kafka Eagle的时候,会遇到一些问题,请教如何解决?今天笔者就在这里总结一下安装步骤,和一些安装的注意事项,以及解决方式. 2.内容 在安装Kafk ...
- hibernate 大对象类型的hibernate映射
在 Java 中, java.lang.String 可用于表示长字符串(长度超过 255), 字节数组 byte[] 可用于存放图片或文件的二进制数据. 此外, 在 JDBC API 中还提供了 j ...
- Struts2标签库常用标签(转)
struts2标签讲解 要使用Struts2的标签,只需要在JSP页面添加如下一行定义即可:<%@ taglib prefix="s" uri="/struts-t ...
- 21.python的模块(Module)和包(Package)
目录 模块(Module)和包(Package) 模块(modue)的概念 模块导入方法 1.import 语句 2.from-import 语句 3.from-import* 语句 4.运行本质 i ...
- hadoop中 namenode的持久化
一.为什么namenode持久化 namenode通过内存存储hdfs集群的元数据(目录结构 文件信息 块对应关系),如果内存出现问题,那么会数据丢失,需要通过持久化,把内存中的数据定期的存储在硬盘中 ...
- MySQL数据库性能优化:表、索引、SQL等
一.MySQL 数据库性能优化之SQL优化 注:这篇文章是以 MySQL 为背景,很多内容同时适用于其他关系型数据库,需要有一些索引知识为基础 优化目标 减少 IO 次数IO永远是数据库最容易瓶颈的地 ...
- 使用vue-quill-editor富文本 实现图片上传
1. 下载并引入 import { quillEditor, Quill } from "vue-quill-editor"; import { container, ImageE ...
- dockerfile部署tomcat+jdk
FROM centos: MAINTAINER www.ctnrs.com ENV VERSION= RUN yum install wget curl unzip iproute net-tools ...
- 中小型企业级 IPS 部署
<构建基于Snort+Guardian+Iptables的IPS> 2020年的第三天,依旧如往常写文章,分享最近做的项目继<中小型企业级防火墙部署>之后的另一部分<构建 ...