最近遇上了一件困扰了我好几天的一个问题,为此排查了一整天都无功而返,想到这感觉真对不起老板,一天一行代码没写,啥也没做成。
背景
事件是这样的,在公司外部新开发了一个性能还没有上线,目前部署在测试环境,Node 服务会开启一个定时工作,每 5 分钟会解决好一部分数据写入到 mysql 数据库中。
在这之前,所有都运行失常,中秋节后下班第一天关上后盾零碎发现没有数据展现了,而后查询数据库发现历史存储的数据都没了,没了。当初只会存储最新的定时工作执行后的数据。可在此之间没有批改过任何代码,这个就神奇了。
头疼工夫
查看写入的数据始终都只会存储最新的数据,则查看是否没有触发更新的逻辑,全副都命中新增的逻辑。
const isExist = await this.Model.findOne({
where: {projectId}
});
if (isExist) {await isExist.destroy()
updateList.push(item)
} else {createList.push(item)
}
当初的逻辑是将新增和更新离开解决,经查看发现所有的 isExist 都是 null,导致全副命中新增的逻辑。可是数据库中明明是有数据的,为什么查问不进去呢?狐疑是有第三方数据存在脏数据之类的状况,所以我将数据库现存数据全副清空,从新写入查看成果。后果第一次写入是失常的,后续还是不会触发更新,通过查问发现每次写入数据库大概十几秒数据就被清空了。
可是在写入后的代码逻辑中是没有执行删除数据的解决,而且每次都是稳固复现,写入后就被删除了,查问无果无奈找到 db 帮找起因。db 查问日志给出的论断就是有定时执行删除的逻辑。
看到日志只能持续在代码中找起因了。因为此时是应用的 sequelize 的 bulkCreate 批量创立数据,所以开始狐疑是不是这个批量解决的过程中呈现了问题,当初是因为每次执行的数据量太多所以没有抉择单条执行,这个时候为了排查问题,所以我改成了单条数据 create 形式创立数据。
this.Model.bulkCreate(list)
批改为
for (const item of list) {this.Model.create(item)
}
后果不出意外的还是定时被删除了,😭
而后开始狐疑是事务没有提交的问题,尽管此逻辑是齐全不须要用到事务操作,但还是抱着狐疑的心态试试看。
let transaction;
try {
// 建设事务对象
transaction = await this.ctx.model.transaction();
for (const item of list) {
// 事务增操作
await this.Model.create(item, {transaction,});
// 提交事务
await transaction.commit();}
} catch (err) {
// 事务回滚
await transaction.rollback();}
后果不出意外的还是定时被删除了,😭😭😭此时曾经没有改变的余地了,此时的天都曾经黑了,可是问题还没解决,只能持续面向百度编程了,此时搜寻到也有同一个人遇到这样的问题,他的解决方案是批改表名称,这时候也只能死马当作活马医了。
后果出意外的恢复正常写入以及更新了。
为什么更改了表名称后就失常呢,思来想去也想不出为什么。后果明天在重新部署服务的时候看了一眼历史部署记录,发现了端倪。就在假期的最初一天早晨有一个部署记录,而后我回看了和最开始产生数据异样的时间段相差无几。根本就能够判定和此次部署有很大的关系,因为公司外部的部署计划有 docker 和虚拟机两种形式,导致每个时间段都会有两个定时工作同时执行,因为数据处理的过程中须要查问第三方数据,最初两边写入的工夫会存在肯定的延时,导致写好的数据被另一边执行了删除的逻辑,因为那台服务器始终未更新批改的代码,始终执行的是最开始那份先删除再更新的逻辑。至于为啥执行了删除然而没有更新,猜测是删除后更新的逻辑出错了。这也是为什么批改了表名称后就失常了,因为那台服务器下面还是旧的代码,新增删除不能读到之前的那张表了,问题到此终于是告一段落了。
收尾
到此是否感觉看了一个大乌龙事件,最终的起因和代码没有任何关系,然而却三番五次的改变无果。在排查过程中还有很多没有写的,比方狐疑反复数据导致所以减少惟一索引,狐疑自增 ID 多大从新清零,然而这个改变的过程中也学到了不少新的常识,如何应用事务,新增惟一索引,批改表名称,重置自增 ID 等很多服务端相干的常识。最初的总结是遇到问题先不要质疑代码,从零碎层面,运行版本,环境变量,运维等方面也要有肯定的思考🤔。
专一前端开发,分享前端相干技术干货,公众号:南城大前端(ID: nanchengfe)