一个线程中断引发Bug的“爆肝”排查经历

背景在之前地版本上线了一个接收大数据推送交易数据文件地接口 , 这个接口要做的逻辑就是解析文件 , 分批入库 。当然为了数据的可靠性 , 以及支持重推 , 最终的流程大概就是这样:
一个线程中断引发Bug的“爆肝”排查经历文章插图
上面的流程就是每日增量文件的处理流程 , 除此之外 , 还有一个历史交易数据的全量文件也需要推送过来 , 这个文件由于只推送一次 , 而且无法按照日期来支持重推 , 所以就约定只推一次(现在看来这里的处理方法是有点粗糙了 。。 ) , 下个版本我将初始化接口对应的代码干掉 。
版本上线后 , 业务在验证时发现不对劲 , 开始在开发业务验证群爆出问题:交易数据对不上! 既然不对 , 那就直接看看数据库 , 很明显的发现 , 数据重复了 , 没错就是约定只推一次的数据现在推了多次 , 因为初始化的全量数据并不支持多次推送 。
果然还是应了那句话 , 需要人为介入的事情 , 总是会有风险 , 关联方的推送开关不知道怎么滴被打开了 , 导致了上线后每天都推送了一遍 , 没有等到我方系统下线对应的接口 。
一个线程中断引发Bug的“爆肝”排查经历文章插图
同时这也证明了 , 「墨菲定律」 。 如果你还不知道什么是墨菲定律 , 那我这里补充下:「如果一件事有发生的可能 , 那么不管几率多少 , 总是会发生的」 , 也可以理解为怕什么 , 来什么 。
这也告诉大家 , 在平时开发相关逻辑接口时 , 一定要考虑各种出错场景 , 假设关联系统都是不可信的 , 确保自己的系统可以应对更多的异常场景 。
对策:因为处于上线后验证期间 , 客户端没有上线 , 只有业务人员在验证使用 , 对应数据库表因为重推了好几份全量的数据导致数据量比较大 , 和运维讨论后决定删表重建后 , 在推一遍数据 。同时对推送文件的处理接口做繁重逻辑:「如果重复推送则直接异常告警」 。
问题出现在提交了重建表的脚本和初始化防重的代码后 , 当天下午移交给测试做功能测试和回归验证 , 准备第二天发布版本 。结果意外发生了 , 在执行解析入库的DB操作时报了获取不到连接异常:
一个线程中断引发Bug的“爆肝”排查经历文章插图
看到这个异常信息后:
### Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; 复制代码想当然的以为是数据库的问题 , 然后考虑到有同事在复现 「数据库重启后应用实例无法重新连接」 的问题 , 第一时间重启了应用实例 , 结果发现依然不行 , 同样的错误 。
既然是获取不到数据库连接 , 那应该整个应用实例都获取不到才对 , 所以去看下Myabtis的操作日志 , 发现其他DAO操作都是正常的 。没办法只能去看下代码 , 到底是哪里的问题 。 定位后发现是在解析数据入库这个环节报错了 , 具体一点就是在解析数据成功后 , 执行插入语句时 , 报了这个获取不到连接的异常 。
排查过程因为这次修复我并没有改解析入库这块的代码 , 只是删表重建 , 然后在 清理数据库(支持重推)这个环节增加了如果数据已存在则直接抛出异常的代码 。
【一个线程中断引发Bug的“爆肝”排查经历】@Overridepublic void clearHistoryData(BigDataFileLogicParam param,String fileName) throws Exception {if (!preCheckFilePass(fileName, 8)) {OpLogUtil.logOpStep("文件预校验", "异常", param.getBizSeq(), param.getDate(), param.getFileId());throw new Exception("data receive has exists!");}}复制代码既然已经走到了解析入库那肯定是没有啥问题了 。
那么自然而然的认为 , 变动点就是删表重建的sql 。 难道是我的建表语句写错了导致Mybatis中的字段映射不对么? 还是我使用的数据库用户新建的表,应用实例数据库连接串使用的用户没有访问权限?
带着这些猜想一个个排查吧 。
经过检查 , 建表语句时一模一样 , 数据库用户也是同一个 , 这就奇了怪了 。
一个线程中断引发Bug的“爆肝”排查经历文章插图
这个时候我发现被我删除重建的这个表的查询语句是没有问题 。而这个时候测试都在等着验证 , 因为第二天下午要发版本 。当时只觉得一顿着急 , 实在看不出来啥问题了 。
既然通过代码和日志不能直接解决问题 , 那就曲线排查吧 。 最原始的方法 , 一个一个排除 , 直接将这条sql语句改为操作其他表 , 排除是因为我删表重建导致出现这个问题 。