点击上方“码农突围”,马上关注 这里是码农充电第一站,回复“666”,获取一份专属大礼包 真爱,请设置“星标”或点个“在看”
错误是如何炼成的
1.上层系统引入的非法参数。对于非法参数引入的错误, 可以通过参数校验和前置条件校验来截获错误;
2.与下层系统交互产生的错误。与下层交互产生的错误, 有两种:
3.本层系统处理出错。
譬如,一个业务用例由场景A.B.C交互完成。实际执行A.B成功了,C失败了,这时B需要根据C返回合理的代码和消息进行回滚并返回给A合理的代码和消息,A根据B的返回进行回滚,并返回给客户端合理的代码和消息。这是一种分段回滚的机制,要求每个场景都必须考虑异常情况下的回滚。
实体在数据库中的记录不存在, 必须指明是哪个实体或实体标识;
实体配置不正确, 必须指明是哪个配置有问题,正确的配置应该是什么;
实体资源不满足条件, 必须指明当前资源是什么,资源要求是什么;
实体操作前置条件不满足, 必须指明需要满足什么前置条件,当前的状态是什么;
实体操作后置校验不满足, 必须指明需要满足什么后置校验, 当前的状态是什么;
性能问题导致超时, 必须指明是什么导致的性能问题,后续如何优化;
多个子系统交互通信出错导致之间的状态或数据不一致?
如何编写更容易排查问题的错误日志
尽可能完整。每一条错误日志都完整描述了:什么场景下发生了什么错误, 什么原因(或者哪些可能原因), 如何解决(或解决提示);
尽可能具体。比如 NC 资源不足, 究竟具体指什么资源不足, 是否可以通过程序直接指明;通用错误,比如 VM NOT EXIST , 要指明在什么场景下发生的,可能便于后续统计的工作。
尽可能直接。最理想的错误日志应该让人在第一直觉下能够知道是什么原因导致,该怎么去解决,而不是还要通过若干步骤去查找真正的原因。
将已有经验集成直接到系统中。所有已经解决过的问题及经验都要尽可能以友好的方式集成到系统中,给新进人员更好的提示,而不是埋藏在其他地方。
排版要整洁有序, 格式统一化规范化。密密麻麻、随笔式的日志看着就揪心, 相当不友好, 也不便于排查问题。
采用多个关键字唯一标识请求,突出显示关键字:时间、实体标识(比如vmname)、操作名称。
登录到应用服务器 -> 打开日志文件 -> 定位到错误日志位置 -> 根据错误日志的线索的指导去排查、确认问题和解决问题。
从登陆到打开日志文件。由于应用服务器有多台, 要逐一登录上去查看实在不方便。需要编写一个工具放在 AG 上直接在 AG 上查看所有服务器日志, 甚至直接筛选出所需要的错误日志。
定位错误日志位置。目前日志的排版密密麻麻,不易定位到错误日志。一般可以先采用"时间"来定位到错误日志的附近前面的地方, 然后使用 实体关键字 / 操作名称 组合来锁定错误日志地方。根据 requestId 定位错误日志虽然比较符合传统,但是要先找到 requestId , 并且不具有描述性。最好能直接根据时间/内容关键字来定位错误日志位置。
分析错误日志。错误日志的内容最好能够更加直接明了, 能够明确指明与当前要排查的问题特征是吻合的, 并且给出重要线索。
if ((storageType == StorageType.dfs1 || storageType == StorageType.dfs2)
&& (zone.hasStorageType(StorageType.io3) || zone.hasStorageType(StorageType.io4))) {
// 进入dfs1 和dfs2 在io3 io4 存储。
} else {
log.info("zone storage type not support, zone: " + zone.getZoneId() + ", storageType: "
+ storageType.name());
throw new BizException(DeviceErrorCode.ZONE_STORAGE_TYPE_NOT_SUPPORT);
}
从某种意义上来说, 错误日志也可以是一种非常有益的文档,记录着各种不合法的运行用例。
catch(Exception ex){
log.error("control ip insert failed", ex);
return new ResultSet<AddControlIpResponse>(
ControlIpErrorCode.ERROR_CONTROL_IP_INSERT_FAILURE);
}
log.error("Get some errors when insert subnet and its IPs into database. Add subnet or IP failure.", e);
log.error("nc has exist, nc ip" + request.getIp());
log.error("nc has exist when want to create nc, please check nc parameters. Given nc ip: " + request.getIp());
log.error("[create nc] nc has exist, please check nc parameters. Given nc ip: " + request.getIp());
log.error("not all vm destroyed, nc id " + request.getNcId());
log.error("[delete nc] some vms [%s] in the nc are not destroyed. nc id: %s", vmNames, request.getNcId());
if(aliMonitorReporter == null) {
log.error("aliMonitorReporter is null!");
} else {
aliMonitorReporter.attach(new ThreadPoolMonitor(namePrefix, asynTaskThreadPool.getThreadPoolExecutor()));
}
log.error("aliMonitorReporter is null, probably not initialized properly, please check configuration in file xxx.");
if (diskWbps == null && diskRbps == null && diskWiops == null && diskRiops == null) {
log.error("none of attribute is specified for modifying");
throw new BizException(DeviceErrorCode.NO_ATTRIBUTE_FOR_MODIFY);
}
log.error("[modify disk attribute] None of [diskWbps,diskRbps,diskWiops,diskRiops] is specified for disk id:" + diskId);
log.error("get gw group ip segment failed. zkPath: " + LockResource.getGwGroupIpSegmnetLockPath(request.getGwGroupId()));
if (!ncResourceService.isNcResourceEnough(ncResourceDO, vmResourceCondition)) {
log.error("disk space is not enough at vm's nc, nc id:" + vmDO.getNcId());
throw new BizException(ResourceErrorCode.ERROR_RESOURCE_NOT_ENOUGH);
}
log.warn("cache status conflict, device id "+deviceDO.getId()+" db status "+deviceDO.getStatus() +", nc status "+ status);
log.warn(String.format("[query cache status] device cache status conflicts between regiondb and nc, status of device '%s' in regiondb is %s , but is %s in nc.", deviceDO.getId(), deviceDO.getStatus(), status));
log.error("[接口名或操作名] [Some Error Msg] happens. [params] [Probably Because]. [Probably need to do].");
log.error(String.format("[接口名或操作名] [Some Error Msg] happens. [%s]. [Probably Because]. [Probably need to do].", params));
log.error("[Some Error Msg] happens to 错误参数或内容 when [in some condition]. [Probably Because]. [Probably need to do].");
log.error(String.format("[Some Error Msg] happens to %s when [in some condition]. [Probably Because]. [Probably need to do].", parameters));
info 用于打印程序应该出现的正常状态信息, 便于追踪定位;
warn 表明系统出现轻微的不合理但不影响运行和使用;
error 表明出现了系统错误和异常,无法正常完成目标操作。
错误现象 -> 错误关键描述 -> 最终的错误原因。
最近有有不少老铁在后台留言说,想进大厂,但是算法不好。最近我整理了一份刷题实录,这份刷题实录,也让我进了心仪的大厂。现在开放分享给大家。希望对大家有所帮助。 任何的算法题,如同写作文一样,都有一些模板可以套用的。比如面试常考的DP(动态规划),难的是一些关键点是否能想清楚。比如你能写出动态转移方程,这题基本上就可以AC了。
整个刷题实录内容,包括 双子针、动态规划、二分查找、贪心算法、深度优先搜索、字符串、递归、字典树、排序、链表等相关专题内容。图文并茂,附有刷题答案源码。 刷题任务的题目,是根据题目的类型来汇总的,总结了八个类别,每个类别下面也总结了5个左右的题型,帮助大家分门别类的突破,所以刷起来相对会更有重点和针对性。如果从头到尾的刷,每周按顺序刷42题,很容易让自己坚持不下来,也会觉得很枯燥。所以在制定计划的时候可以让这个计划变得更“有趣"和针对性,让它看起来更容易实现一点,才会更容易坚持。 目前上述内容已打包成完整电子书,具体获取方式如下:
扫描关注 程序猿进阶 公众号;
在 程序猿进阶 公众号后台回复关键词「9999」获取下载地址。
扫描关注,回复"9999"即可下载 最近热文
• 阿里中台搞了3年,凉了?网传:副总裁玄难“背锅”,辞职创业!咸鱼放弃维护 FlutterGo! • 字节跳动员工晒出税后工资,网友:怀疑你是日薪 • 华为员工违规领夜宵被发现后,被罚冻薪降考评,终身不得领夜宵,HR:哪个员工上班健身,定性考勤造假 • B站,被扫黄了!!!
在这里,我为大家准备了一份2020年最新最全的《Java面试题及答案V3.0》,这套电子书涵盖了诸多后端技术栈的面试题和答案,相信可以帮助大家在最短的时间内复习Java后端的大多数面试题,从而拿到自己心仪的offer。 截了张图,大家可以仔细查看左边的菜单栏,覆盖的知识面真的很广,而且质量都很不错。 资料获取方法
扫描下方二维码
后台回复关键词:Java核心整理
明天见(。・ω・。)