15种线上Bug梳理,这坑我算是踩全了!

15种线上Bug梳理,这坑我算是踩全了!
软件测试面试刷题,这个小程序(永久刷题),靠它可以快速找到工作!https://blog.csdn.net/AI_Green/

软件测试面试刷题,这个小程序(永久刷题),靠它可以快速找到工作!https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502编辑https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502https://blog.csdn.net/AI_Green/article/details/134931243?spm=1001.2014.3001.5502

在我们日常的开发过程中,我们都会时不时地遇到问题。最常见的一句话是“本地运行安全吗?”在测试环境中运行一切正常吗?在预发布环境中这正常吗?

为什么我有时会看到一些有关生产的早期警告?

一般来说,这种情况最常是由特定条件或多种因素引起的“偶然问题”引起的。

后来,由于这种幼稚、幻想的想法,我遭受了一些损失,但与能够稳定重现的bug相比,“偶尔出现的问题”更为致命,我开始越来越意识到,这往往可以是毁灭性的打击。

我在网上看到一篇相关的总结文章,觉得写得很好,所以分享给大家,以提醒我也遇到过的坑。

我将总结过去几年中不时出现的一些问题。

偶发问题具有一定的隐秘性,我们需要有精神,即使偶发问题也作为问题去探究。

如果您在上线前没有确定偶尔出现问题的原因,那么上线后排除故障就会变得更加困难。

您的环境可能与我们不同,因此我们常常无法模拟和重现该问题,但过去几年我们遇到过很多这样的场景,最近我已经整理出来了。

这篇文章的结构安排如下。第一部分列出场景,第二部分列出案例。

一 场景罗列

偶尔出现的问题可能是高概率或低概率的问题,可能只发生一次,也可能最初不发生,可能在运行一段时间后才发生。

大多数问题都是由松散的编码甚至低级错误引起的。

第一类:并发访问、异步编程、资源竞争

第二类:缓存相关,缓存一致性

数据库、本地缓存和分布式缓存数据是一个常见问题,由于编码考虑不周,它会给企业带来问题。

请注意,由于缓存不一致持续的时间很短,因此缓存一致性常常被忽略,从而导致杂散调查和更长的调查时间。

第三类:脏数据、数据倾斜

脏数据通常会导致异常行为,并且是偶发问题的常见区域。现在我们切换到脏数据可能性更大的场景。

脏数据会引发异常。常见情况:selectOne,但是查询找到两个结果。

第四类:边界值、超时、限流

上游业务链路较长,异常情况需要翻译,导致故障排查难度加大。

第五类:服务器、硬件

第六类:程序代码

不兼容的数据结构、不兼容的请求参数、不兼容的方法等。程序尚未发布兼容性,尚未完全关闭,正在中断正在处理的任务。像这样的发布是一场灾难。

第七类:网络等其他

二 案例描述

非线程安全集合类

非线程安全的集合类用于并行流中,集合对象返回的结果可能不正确。

当数据量较小时,问题很难发现,当数据量较大时,问题更加明显。

ListXXXDO dataList=从数据库获取结果集合

//非线程安全集合

ListXXXDO successList=new ArrayList();

ListXXXDO 失败列表=new ArrayList();

//ParallelStream 在并行流中使用不安全集合

dataList.ParallelStream().forEach(

沃-{

……

if (执行成功) {

successList.add(vo);

} 除此之外{

失败列表.add(vo);

}

}

);

它以流的形式开始,没有任何问题。

当数据量较大时,我进行了优化,将流改为ParallelStream,但是当线上数据量较大时,由于数据量较小,我无法发现问题。

ThreadLocal

使用ThreadLocal 时,remove 方法无法正确执行。这可能是由于抛出异常造成的。特殊情况下会复用线程,ThreadLocal中的数据符合预期。

注意:这是由松散的编码引起的。

//一般情况下,可以执行remove。

尝试{

.

} 最后{

threadLocalUser.remove();

}

由于不严格,所以不执行删除操作。

//错误用法

尝试{

.

//业务异常。执行删除失败。

threadLocalUser.remove();

} catch(异常异常){

.

}

ThreadLocal其实有很多应用场景,但是用完后要记得去掉。它重复使用线程,使得故障排除变得困难。

修改成员变量

从配置中心读取配置信息,实例运行时将数据作为带有占位符的模板,通过上下文参数解析占位符。比如发送短信、卡片等。

{

“已批准”:{

\’themeHeader\’:\’分发许可协议\’,

\’contentDesc\’:\’交付工程师: ($userName$) 正在请求您的交付许可\’,

\’keyNote\’:\’特别注意:如果您不签收,交付工程师将无法交付\’,

\’redirectLinkText\’:\’立即进行身份验证\’,

\’tenantId\’:\’您的组织“$tenantId$”具有以下需要批准的权限: \’

}

}

这是一段模板数据,其中占位符被上下文替换。

//从配置中心读取配置并与成员变量一起保存

公共类CardSceneParamConfig 实现XXXDataCallback {;

//从nacos配置中读取初始化模板数据

私有MapString, AuthorizedCardParamVO CardParamVO=new HashMap();

.

//获取配置模板

公共AuthorizedCardParamVO getAuthorizedCardParamVO(字符串场景代码){

返回卡ParamVO.get(场景代码);

}

}

//获取模板对象并修改模板中的占位符。

私人AuthorizedCardParamVO xxx(AuthorizedCardParamVO稳定,MapString,字符串参数){

.

最终字符串contentDescStr=Optional.ofNullable(stable.getContentDesc())

.map(contentDesc – contentDesc.replace(\’$userName$\’, params.get(\’userName\’)))

.orElse(stable.getContentDesc());

//改变成员变量

stable.setContentDesc(contentDescStr);

……

动态返回。

}

stable.setContentDesc(contentDescStr); \’contentDesc\’:\’ 交付工程师: ($userName$) 已向您请求交付许可,因为成员变量已更改。

这将更改为特定值“contentDesc”:“交付工程师: (XXXX) 请求交付许可”。

如果用户名是同一个人或者初始请求是针对不同的机器,则没有问题。如果没有,你就有麻烦了。

修改成员变量时必须特别小心。改变成员变量的情况多次发生。需要保持警惕。

异步依赖

它使用线程池运行,但将结果添加到列表是异步的。即使代码运行,列表结果集合也可能不包含任何数据。异步依赖。

ListXXXDO dataList=从数据库获取结果集合

//非线程安全集合

ListXXXDO successList=new ArrayList();

ListXXXDO 失败列表=new ArrayList();

for (XXXDO vo : 数据列表) {

ThreadUtil.execute(() – {

//API操作vo

……

if (执行成功) {

successList.add(vo);

} 除此之外{

失败列表.add(vo);

}

});

}

//可能没有获取到就返回执行结果。

这是一个低级错误,需要异步等待,但由于数据量较小,因此没有注意到该问题。如果数据量很大,很容易泄露。

很久以前,我从前伴侣那里继承了一个密码,现在我相信这是一个陷阱。

上传Excel数据,在服务器上进行分析,并将分析结果上传到Redis。这个解析过程也是一个异步操作。

客户端完成上传后,点击“发送数据”即可从redis中检索数据并保存到DB中。

如果数据很大,您会注意到没有数据被插入到数据库中。

主要有两个原因。

提交时Redis中没有数据,因为解析不完整。

提交按钮慢并且redis解析的数据过期

如果数据量较小,则该特征不常用,因此如果数据量较大,则很难发现。

并发性修改

在以下情况下,counter++ 上的操作不是原子的并且同时发生变化:周期太少可能不会导致问题。

循环计数计数器不符合预期。

公共类UnsafeConcurrencyExample {

私有静态int 计数器=0;

公共静态无效主(字符串[] args){

线程thread1=新线程(() – {

for (int i=0; i 1000; i++) {

计数器++;

}

});

线程thread2=新线程(() – {

for (int i=0; i 1000; i++) {

计数器++;

}

});

线程1.start();

线程2.start();

尝试{

线程1.join();

thread2.join();

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(\’Counter:\’ + 计数器);

}

}

数据不一致

第一次运行此代码时,将从数据库检索数据并将其放入缓存中。

如果10分钟内再次运行该代码,将直接从缓存中获取数据,而无需再次访问数据库。只有当缓存过期时,才会再次从数据库中检索新数据。

公共类CacheExample {

//创建缓存

私有静态CacheString,对象缓存=CacheBuilder.newBuilder()

.expireAfterWrite(10, TimeUnit.MINUTES) //设置缓存过期时间为10分钟

。建造();

公共静态无效主(字符串[] args){

String key=\’data\’ //缓存的键

//从缓存中获取数据。如果缓存中不存在该数据,则会从数据库中检索。

对象数据=cache.get(key, () – fetchDataFromDB());

System.out.println(\’Data:\’ + data);

}

//模拟从数据库中检索数据

私有静态对象fetchDataFromDB() {

//从数据库获取数据的逻辑

System.out.println(\’正在从数据库中检索数据.\’);

返回“来自数据库的数据”。

}

}

由于缓存过长,有些部分更新了,有些部分仍然陈旧,导致数据性能不稳定。

由于数据一致性问题,对不同服务器节点的请求效果不同。

未考虑优雅关闭

如果提交到线程池的任务没有正确关闭,极端情况下可能会出现脏数据,从而出现偶发性问题。

下面是一个使用线程池的简单示例,但是下面的线程池并没有考虑到正常关闭。

公共类SimpleThreadPool {

私有ExecutorService执行器。

公共SimpleThreadPool(int 线程) {

executor=Executors.newFixedThreadPool(线程);

}

公共voidexecute(可执行任务){

执行器.execute(任务);

}

公共无效关闭(){

执行器.shutdown();

}

}

使用execute、reissue、restart、异常中断等执行任务时任务执行中断,产生脏数据。

脏数据导致查询结果多条

我使用selectOne 方法查询数据库中的数据但找到多个条目

com.baomidou.mybatisplus.core.Exceptions.MybatisPlusException: 期望一条记录,但查询结果是多条记录] 有根本原因

边界值触发限流

许多年前发生过一件事。

需求场景是批量向IM群发送卡片。由于特定场景,满足场景的卡数据量较大,在300条左右,触发限流。

经过多次服务将原始错误转化为一般异常,这也增加了故障排除的成本。

限流异常错误不予考虑,统一处理并转换为切面级别的系统异常。

边界值有时会引起问题,尤其是无法模拟真实客户场景时,原始错误信息的丢失增加了故障排除难度。

数据量带来的限流问题有很多。由于原始错误异常转化为链路上的其他异常的情况很常见,因此应进一步考虑这种情况,以增加系统的健壮性。系统。

机器中存在机器异常

批量发布时机器未正常下线。

该IP不会因为节点不健康而被删除。

这可能会导致以下问题:

下游RPC请求异常。服务依赖方异常。

本机请求异常

MQ消费异常

……

集群健康状况非常重要。

因为磁盘打满而出现机器挂了

服务已关闭:您的设备上没有可用空间

集群中某台机器磁盘满了,挂起,路由到这台机器超时。其他机器可以正常访问它。

需要检查集群,发现异常立即删除机器。

数据不在同一个事务内

例如,updateBalance是一个独立的事务,因此帐户A可能会耗尽余额并遇到麻烦,从而导致异常。

//假设这是一个转账操作,将钱从账户A 发送到账户B。

updateBalance(connection, \’B\’, 100); //给B账户添加100元

//A账户资金不足

updateBalance(connection, \’A\’, -100); //A账户减去100元

网络入口带宽不足

这是一个小作坊里的故事。我在开发阶段购买了阿里云服务器。当时的网络带宽是1M,在测试阶段这不是问题。

随着用户数量的增加,发现部分客户请求不断超时,最终确定问题是由于网络带宽不足造成的。

压力测试和网络监控非常重要

DDos攻击等导致正常用户异常

存在正常用户异常。带宽资源被抢占。

rpc 超时

假设客户端向服务器发送请求以检索用户信息,并将超时设置为5 秒。

客户端期望在5秒内收到服务器返回的用户信息。然而,在某些情况下,由于网络延迟,服务器端响应可能要等到超时时间过后才能到达客户端。

服务器端由于运行时间较长,也可能存在性能问题。

内存泄漏

尽管这个故事发生在很多年前,但对我来说,它仍然是一个所有16 台在线机器突然出现内存峰值的事件。

生意是通行证

过计件算工资;程序是输入表达式运算结果。

服务刚上线, 测试边界值,因为输入一个很大的值,导致类型溢出;是计算工资的方法,程序设置了出错重试。

本来是单例的对象,但是却在每次执行方法时被创建
因为错误发生,这个方法被发送到 mq 进行重试
但是 mq 未设置最大重试次数
因为集群机器都监听这个 mq,导致错误被不断地发送到 mq,形成了死循环。对象被无限创建,导致集群机器内存全部飙高。

历历在目的例子……

三 总结

场景还远远不止上面罗列的这些,但根据这些场景也总结了一些经验:

合理的代码编写,很多问题都是编码导致,甚至还有很多低级错误
多考虑边界值,边界值常常因为不会发生而被忽略
合理的日志,方便排查,没有日志的异常增加排查难度
别随便转换异常,做好异常处理
压测,数据大会提前暴露并发相关问题
别吞掉异常,否则出现错误时不容易排查,偶发性问题就变成灵异事件了
机器一定要有完善的监控。包括上下游的监控,否则其中 1 个节点出现问题,整个链路都会因为这个节点出现偶发性的问题。
做好优雅关闭等

很多偶现的问题排查也十分困难,遇到了就是一个很好的训练机会,当排查问题多了,经验就足了,再遇到相似问题就能轻轻搞定了。像网络问题排查比较麻烦,平时多学习工具,技多不压身。

最后: 下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保证100%免费】

​​​软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。


#以上关于15种线上Bug梳理,这坑我算是踩全了!的相关内容来源网络仅供参考,相关信息请以官方公告为准!

原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/92138.html

(0)
CSDN的头像CSDN
上一篇 2024年6月25日
下一篇 2024年6月25日

相关推荐

  • 网格布局

    1:基本布局Grid 布局是二维的基于网格的布局系统,它可以同时处理列和行(这是对比flex弹性盒模型布局而言);第一个专门为解决布局问题而生的CSS模块。几个

    2024年9月1日
    0
  • Quartz启动过程分析

    昨天写了篇SpringBoot整合Quartz的文章,然后也正巧不知道写什么了,就带着好奇写了这篇文章,明天的话再谈一谈执行流程。一、简要1.1、quartz

    2024年9月1日
    0
  • 教育机构编程教具是什么

    教育机构编程教具是一组设计用于辅助和提高学生编程学习的工具和设备,它们包括计算机软件、硬件和多媒体资源、1、便于学生理解编程概念、2、促进实践操作能力、3、激发学生的兴趣和创造力。…

    网站运维 2024年5月12日
    0
  • Crypto++ 入门(cryptocoin)

    Crypto++ 入门一、简介
    Crypto(也称为CryptoPP、libcrypto或cryptlib)是一个免费的开源C库,提供了多种加密方案。它由Wei Dai开发和维护,广

    网站运维 2024年6月25日
    0

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注