记一行代码顺序引起的事故

在这里插入图片描述

01 前情回顾

在这里跟同学们分享一个前几天在线上遇见的 bug…

bug描述:客户端轮询服务端接口获取数据做打字机效果展示,会偶现输出到一半就停止不动了,但是数据还没输出完(如下图,到红色部分就卡住了)。
在这里插入图片描述

老泪纵横 😭😭😭

说一下业务场景::

  • 这是一个大模型问答的服务
  • 我方服务端通过 sse 的方式对接三方大模型
  • 我方服务端将请求到的数据通过一个 nextKey 进行缓存
  • 我方客户端异步轮询到服务端获取数据

以上简单的概括了一下大致场景,当然细节还是比较多的,这里有同学可能会有疑问:服务端获取到三方的流直接返回给客户端不就好了吗,为啥还要将数据放到缓存再去异步获取呢? 这不费劲吗? 确实,但是为了避免一些复杂的业务所以就不得不这么做了,比如:复杂的数据结构、多模态,ios、安卓、鸿蒙对于 sse 的适配等。

02 步入正题

我先将修改之前的代码贴出来,大家看看能不能找出问题

public CommonResponse<CommonChatVO> tmpData(String nextKey) {
        LocalUser user = LocalUserUtils.getUser();
        String key = CommonConstant.TMP_DATA_KEY_REDIS + nextKey;
        log.info("获取缓存临时数据请求信息: nextKey:{}, username:{}", nextKey, user.getUsername());

        CommonChatVO result = null;
        int attempts = 0;
        while (attempts < tmpDataProperties.getNum()) {
            try {
                result = (CommonChatVO) redisManager.get(key);
                if (result != null) {
                    if (result.getStatus() == 1) {
                        log.info("获取数据结束, status=1, 用户标识:{}, nextKey:{}", user.getUsername(), nextKey);
                    }
                    break; // 一旦找到数据,就跳出循环
                }
                Thread.sleep(tmpDataProperties.getWaitTime()); // 如果没有数据,则等待
                attempts++;
            } catch (InterruptedException e) {
                // 处理中断,可能需要记录错误或返回错误响应
                Thread.currentThread().interrupt(); // 重新设置中断状态
                log.error("轮询过程被中断", e);
            }
        }
        redisManager.del(key);
        return CommonResponse.success(result);
    }

简单解释一下上面的代码:

  • 客户端轮询调用这个接口获取数据,当获取到一个固定的 type 就结束获取,当然这里一定要有一个前提就是如果数据的存储方异常或者失败一定要考虑容错,异常的话也要想办法更新这个结束状态,不然客户端会一直获取。
  • 然后服务端为了提升效率在后台用一个while循环去缓存获取数据,结束条件是到达固定的次数或者获取到数据就结束,如果没有获取到并且没有达到阈值那就等待固定的时间再次获取。

上面的代码会有啥 bug 呢
在这里插入图片描述
在代码的最后会执行一次删除 key 的操作,乍一看删除 key 也没啥问题 为了避免内存被浪费 获取到数据就把缓存删掉,如果没获取到数据删掉好像也没事(因为缓存里压根也没有)

但是在快速的持续写入和持续获取数据的时候问题就出现了

比如:我们判断缓存中没有数据,然后在在判断之后代码没有进到 if 代码快中,这个时候另一个线程将数据写到了缓存,然后我们的代码恰好又执行到了删除 key 的地方,这里就将刚刚存起来的数据给删掉了, 然后出现的问题就是客户端一直去服务端获取数据一直获取不到,因为数据已经被删掉了,也没有给客户端同学返回结束状态,就出现了本次的 bug。

最后将改造后的代码贴出来

public CommonResponse<CommonChatVO> tmpData(String nextKey) {
        LocalUser user = LocalUserUtils.getUser();
        String key = CommonConstant.TMP_DATA_KEY_REDIS + nextKey;
        log.info("获取缓存临时数据请求信息: nextKey:{}, username:{}", nextKey, user.getUsername());

        CommonChatVO result = null;
        int attempts = 0;
        while (attempts < tmpDataProperties.getNum()) {
            try {
                result = (CommonChatVO) redisManager.get(key);
                if (result != null) {
                    if (result.getStatus() == 1) {
                        log.info("获取数据结束, status=1, 用户标识:{}, nextKey:{}", user.getUsername(), nextKey);
                    }
                    redisManager.del(key);
                    break; // 一旦找到数据,就跳出循环
                }
                Thread.sleep(tmpDataProperties.getWaitTime()); // 如果没有数据,则等待
                attempts++;
            } catch (InterruptedException e) {
                // 处理中断,可能需要记录错误或返回错误响应
                Thread.currentThread().interrupt(); // 重新设置中断状态
                log.error("轮询过程被中断", e);
            }
        }
        return CommonResponse.success(result);
    }

同学们一定要注意 获取到数据之后再执行删除操作,或者是设置超时时间(本次其实是设置了超时时间的),多余删啊。。。

这个业务场景大家还有没有其他的解决方案或者优化方案 希望留言~

本篇文章到这里就结束了,最后送大家一句话:
喷泉之所以好看 是因为他有压力;瀑布之所以壮观 是因为没有退路;滴水之所以穿石 是因为贵在坚持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/898603.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Axure高保真原型】移动案例

今天和大家分享多个常用的移动案例的原型模板&#xff0c;包括轮盘滑动控制元件移动、页面按钮控制元件移动、鼠标单击控制元件移动、元件跟随鼠标移动、鼠标拖动控制元件移动、键盘方向键控制元件移动&#xff0c;具体效果可以点击下方视频观看或打开下方预览地址查看哦 【原…

虚拟装配解决方案:在虚拟现实中实现移动零件与三维模型碰撞检测

装配过程占产品开发时间和成本的很大一部分。在投入生产前对产品装配进行碰撞检测能够有效的降低因设计疏忽所导致的重复试错所导致的成本增加&#xff0c;并进一步降低设计审核整体流程所需时间。 选择、移动和操作3D模型的各个部分 TechViz多通道软件具有通用零件识别引擎&am…

Core webapi<1>特性 Route、Bind、HttpGet、Consumes、Produces

微软资料 Consumes Produces 让 API 返回 text/json 类型的数据。因为默认情况下&#xff0c;API 返回数据使用 application/json 格式&#xff0c;所以&#xff0c;咱们要改为 text/json&#xff0c;就得用 Produces 特性。

Java最全面试题->Java基础面试题->JavaEE面试题->Web应用服务器面试题

文章目录 Web应用服务器面试题Tomcat是什么?Tomcat缺省端口是多少&#xff0c;如何修改&#xff1f;Tomcat 有那几种Connector 运行模式&#xff1f;什么是Servlet&#xff1f;Servlet请求过程&#xff1f;Tomcat执行流程&#xff1f;Tomcat部署方式?什么是JBoss ?在JBoss 7…

UG NX12.0建模入门笔记:1.1 UG界面编辑

文章目录 一、用户默认设置&#xff1a;修改新建零件时的默认存储路径。二、用户默认设置&#xff1a;修改默认图纸的尺寸单位。三、如何移除不需要的工具栏&#xff1f;四、如何将角色设置成高级&#xff0c;以使用更多的功能&#xff1f;五、如何修改软件背景颜色&#xff1f…

w~自动驾驶合集9

我自己的原文哦~ https://blog.51cto.com/whaosoft/12320882 #自动驾驶数据集全面调研 自动驾驶技术在硬件和深度学习方法的最新进展中迅速发展&#xff0c;并展现出令人期待的性能。高质量的数据集对于开发可靠的自动驾驶算法至关重要。先前的数据集调研试图回顾这些数据集&…

取得六西格玛绿带培训证书有什么用?

六西格玛作为一套科学的管理方法和工具&#xff0c;已被广泛应用于各个行业。而六西格玛绿带培训证书&#xff0c;作为这一体系中的基础认证&#xff0c;不仅是对个人专业能力的认可&#xff0c;更是职业生涯中的一大助力。本文&#xff0c;天行健企业管理咨询公司旨在分享取得…

山东济南杰出思想家颜廷利:升命学说,当今世界前沿哲学思想

颜廷利教授的"升命学说"是一个将现代科技发展与中华传统文化相结合的当今世界前沿哲学教育理论框架&#xff0c;它是在传统哲学基础上的一种目前社会创新性思想体系。为了理解"升命学说"与传统哲学的不同之处&#xff0c;我们可以从以下几个方面来探讨&…

通过docker desktop拉取镜像打包镜像传输到其它服务器中

通过docker desktop拉取镜像打包镜像传输到其它服务器中 使用 docker save 命令将镜像保存为 tar 文件 docker save -o <path-for-tar-file> <image-name-with-tag>例如&#xff0c;如果想要保存名为 myimage:latest 的镜像&#xff0c;并将其保存到当前目录的 m…

【K8S系列】Kubernetes node节点NotReady问题及解决方案详解【已解决】

Kubernetes 集群中的每个节点都是运行容器化应用的基础。当节点状态显示为 NotReady 时,意味着该节点无法正常工作,这可能会导致 Pod 无法调度,从而影响整个应用的可用性。本文将深入分析节点不健康的各种原因、详细的排查步骤以及有效的解决方案。 一、节点不健康的原因 节…

Leetcode—1226. 哲学家进餐【中等】(多线程)

2024每日刷题&#xff08;185&#xff09; Leetcode—1226. 哲学家进餐 C实现代码 class DiningPhilosophers { public:mutex mx;DiningPhilosophers() {}void wantsToEat(int philosopher,function<void()> pickLeftFork,function<void()> pickRightFork,functi…

双十一开启极速达夜派;黑神话获泰国年度最佳游戏;AI 模型可帮助识别 17000 多种疾病的候选药物....| 网易数智日报

双 11 菜鸟在北京、上海、广州、杭州等城市开启「预售极速达夜派」服务 10 月 21 日&#xff0c;菜鸟在北京、上海、广州、杭州等城市开启「预售极速达夜派」服务&#xff0c;批量大促包裹实现小时级送达。 据介绍&#xff0c;在消费者支付尾款前&#xff0c;菜鸟供应链就已经…

闯关leetcode——190. Reverse Bits

大纲 题目地址内容 解题代码地址 题目 地址 https://leetcode.com/problems/reverse-bits/description/ 内容 Reverse bits of a given 32 bits unsigned integer. Note: Note that in some languages, such as Java, there is no unsigned integer type. In this case, …

使用excel.js(layui-excel)进行layui多级表头导出,根据单元格内容设置背景颜色,并将导出函数添加到toolbar

本段是菜狗子的碎碎念&#xff0c;解决办法请直接从第二段开始看。layui多级表头的导出&#xff0c;弄了两天才搞定&#xff0c;中途一度想放弃&#xff0c;还好坚持下来了。一开始用的是layui的toolbar里自带的那个导出&#xff0c;但是多级表头没有正常导出&#xff0c;单元格…

ORACLE SELECT INTO 赋值为空,抛出 NO DATA FOUND 异常

例子&#xff1a; DECLARE ORDER_NUM VARCHAR2(20); BEGIN SELECT S.ORDER_NUM INTO ORDER_NUM FROM SALES_ORDER S WHERE S.ID122344; DBMS_OUTPUT.PUT_LINE(单号: || ORDER_NUM); END; 在查询结果为空的情况下&#xff0c;以上代码会报错&#xff1a;未找到任何数据 解决方…

深度学习——循环神经网络RNN知识点小结(全)

前置知识: 序列模型--输出/输入中包含有序列数据的模型 特点: 1.输入/输出元素之间具有顺序关系, 不同顺序得到的结果不同 2.输入输出不定长, 比如问答系统, 聊天机器人 DL--RNN 小名:循环神经网络 外国小名: sequence model 定义: 专门设计用来处理序列数据的神经网络 应用: …

2024临床常用的营养评价量表汇总!

临床常用量表来评估患者的营养状况、营养摄入风险&#xff0c;常笑医学整理了5个临床常用的营养评价量表&#xff0c;包括SGA营养评价表、老年营养风险指数、营养风险筛查评分简表、简易营养评价精法量表、微型营养评估量表等。这些量表在常笑医学网均支持在线评估、下载和创建…

(四)问题记录:matlab中spatial contact force模块下关于stiffness(刚度)的设定

最近在搞一阶倒立摆&#xff0c;在matlab仿真时遇到这样的问题&#xff1a;stiffness设置为10e5就会发生碰撞后穿透&#xff0c;&#xff08;四个spatial contact force模块是分别连接小车四个轮子和地面的&#xff09; 而设置成10e6就不会有问题&#xff0c; 由于本人也是第一…

cefsharp 88.2.90.0(Chromium 88.0.4324.182)支持H264视频播放-PDF预览 老版本回顾系列体验-100以下版本

一、关于此版本 Cef 88.2.9/CefSharp 88.2.90/Chromium 88.0.4324.182/支持H264/支持PDF预览 支持PDF预览和H264推荐版本 63/79/84/88/100/111/125 框架:NET4.5.2,X86 注意运行环境支持变化1.1 扩展(关于DPI黑边框问题解决) this.AutoScaleMode = AutoScaleMode.Dpi;

QT 机器视觉 1.相机类型

本专栏从实际需求场景出发详细还原、分别介绍大型工业化场景、专业实验室场景、自动化生产线场景、各种视觉检测物体场景介绍本专栏应用场景 更适合涉及到视觉相关工作者、包括但不限于一线操作人员、现场实施人员、项目相关维护人员&#xff0c;希望了解2D、3D相机视觉相关操作…