架构的优化往往不是因为事先考虑多完美,而是来自于现实的刺痛。
场景一:
一个批次的数据处理时间平均30秒,乍一看没什么问题。但是当每月的批次数量有2万多的时候,整体时间就是1万分钟,大约要7天时间。而程序只能串行,不能多批次并行处理。
如果时间整体比较宽裕,问题也不大。但是客户要求一周完成一个月度数据体量的整体工作。而这个7天的执行工作只是整个月度工作的一部分,所以时间就显得非常宝贵。
于是在不改变主体逻辑的情况下,写了一个外挂,整体时间提升到1-2天。简单点说就是按照一定的逻辑把多个批次先捏合成一个大批次,执行完成后再在数据结果中恢复成原来的批次特征。这样单个批次的运行时间拉长了,但是因为执行次数极度减少(比如可以把5千个小批次捏合成一个,整体操作时间从原执行40小时的时间减少到半小时内)。
这样人工干预越多,时间执行越快。而一些大数据量的批次则可以在晚上的时候按照原来的方式跑。从而这个时间不再是瓶颈。
优化思路:
如果串行不可避免,那就把管道加粗,一次将同类型多个批次一起执行。简单的说就是用 (等于一个批次号),调整为(in 一堆批次号)。
场景二:
而另外一个情况的发生,发生了两次。基本都发生在晚上加班到人已经发呆的时点,简单机械的操作。
系统通过批次状态位判断拉起的需要处理的批次。比如我需要处理某100个,但是此时批次状态表中符合状态的批次有上万个。本来应该把其他的状态临时置掉,只开放这100个。但是只检查了这100个后就拉起了程序,导致其他上万个也被拉起。导致一次半小时的作业被拖到10小时,一次1小时的作业被拖到40小时。
程序本身没有提供停的功能(系统本身的处理机制也控制了即使某个批次报错也会跑到下个批次,所以无论是破坏数据还是破坏表都拦不下程序),而且在生产环境没权限杀进程。如果申请权限杀进程,就会引发一个高级别的运维事件,也是不可承受的。
优化思路:
如果操作失误不可避免,那就考虑及时止损。在批次执行前进行控制状态扫描。每个批次扫一次扫描状态有点不划算,那就可以每10次或20次扫一次。增加一点点时间消耗增加灵活性。
场景三:
某接口设置定时任务,一小时执行一次。但是遇到一个轮次批次过多或者数据量较大时,一小时执行未完成,下个轮次自动起来了。此时新任务会把新产生的批次以及上一轮次没处理完的批次一起拉起来。而且处理过程中因为用到同一组临时表且部分表是每次全部清理的(也是不能并行的原因,当然本身也是考虑性能原因),所以两个任务起来会相互影响造成数据结果错误。
优化思路:
简单粗糙一点,增加一个任务状态表。同一任务执行时把自己标记为run状态,下一任务到点拉起时扫描状态位,前序没有执行完,则跳出本次执行任务。
评论区