本文已参与 周末学习计划,点击查看详情
这是我参与更文挑战的第 6 天,活动详情查看:更文挑战
发现问题
一般需要推送的粉丝量都维持在 3w-7w之间,为了确保安全不出错,便每次按照 1w 的量导入到推文粉丝表内,接着去执行一次发送接口。
很长时间,这个接口都是这样用的,图文推送方面也没出现什么问题。然而,近期需要执行一份 150w 量的图文推送任务,于是就很小步的尝试一下 2w 量的发送情况。意想不到的情况发生了。
根据日志统计,推送出去大概 1.3w 条的时候,日志就断掉了,接口直接响应超时了。上一篇文章中有对这个接口内部的功能实现步骤进行了描述。里面有提到说在发送完推文后,还会把处理状态回写到表里。这时去数据库里查表。发现那 2w 条数据并没有更新,状态还是“未发送[0]”。
这种情况下,批量发送 2w 是不可能的了,刚刚那一批 2w 是从哪一条结束的,单纯依赖日志,受顺序影响,也查不出来了。
按照 1w 的量批量操作,那发送 150w,今晚还能回家吗?
分析问题
在反复确认接口方法的功能实现,确实是没什么问题的,毕竟 1w 条都是正常发送出去的。在批量发送的过程中,日志中已经打印出来了调取微信接口的过程了,但其实这时候我因为想尽快导入下一批 1w 的数据,就会去数据里刷新,但每次都发现数据没有更新,连“发送中[1]”的状态都没有更新,只是过了一段时间,发现日志不走了,刷新数据库会发现状态全变成“已发送[2]”。这就很迷了。
按理来说,会先经历中间那个状态。沿着这个思路去思考,会觉得这种数据处理方式和一种机制很像。对,操作被加了事务。
解决问题
方法内部从调用外部接口到数据更新层都没有找到事务的控制。方法上面也没有被加事务。于是很自然的往类上面去找,果然,这个类上面被加了 @Transaction。
把事务控制移除后,这里有一点提一下,因为用的 JPA ,之前有事务的情况,保存方法调用的 save ,而现在不加事务,需要在更新完就立刻提交,所以要将 save 方法改成 saveAndFlush, 否则,数据更新不会生效。
重新批量导入 3w 的量,开始推送时,此时立刻去到数据库刷新时,就会立刻发现数据不停的在更新状态。
之前是 8-10min 完成一批 1w 的推文量,总任务结束估算要等几个小时了。现在观察是 1-2min 就可以将第二批 1w 的数据导入进去,因为后续调微信接口是异步线程调用,也就不妨碍数据导入。紧接着,尝试用 2w、4w 一批的数据,都没有什么问题,最终剩下的8w一次性导入发送出去。总体人工等待加耗时不过半小时。
问题复盘
别的数据处理接口都是加事务,正如前人所写的这个接口一样。而在优化的时候要去掉事务。这当然是结合这个接口要实现的目的来处理的。这个接口里面涉及的数据本身只作一个读取的作用,后续也不会被作为业务数据使用,完全没必要加上事务控制。况且发送推文这件事情,少几条数据没有更新到,多几条数据更新多了,也不是非常严重的事情,就更没有必要加上事务控制了。
事务机制还是要结合业务需求来使用,不是看到数据操作就加上事务。
备注
问题背景说明请移步此篇文章:juejin.cn/post/697033…