最近由于公司业务发展需要,要重构一个自己一年前写的服务,好在老版本一直在维护更新,所以绝大部分的逻辑和老版本的架构还是比较清晰的,重构起来难度不是太大。
用了将近4周的时间,终于重构完整个服务模块,重构期间也根据不同的进度做了测试,测试更多的是倾向于接口通不通,整体还算顺利,期间虽然也有bug,但都不是太致命,稍微调整下就能正常运行,等到所有重构工作完成后,大测试开始了。
按照重构后的测试要求,开始最后一个阶段的冲刺,整个重构工作让我痛苦了好几天的地方也正是出现在这个阶段。
首先,一开始测试的时候发现只能达到目标要求的70%,剩下的目标始任务终达不到,花了将近一天时间排查达不到的原因,一开始以为是代码写的有问题,所以又重新梳理了一遍代码,并没有发现什么异常情况。后来经过领导的提示,检测了下程序运行时服务器的各项参数,发现测试到目标要求的70%时,也正是服务器的内存资源不到1G的时候,再单独看每个容器耗费内存的情况,也由刚运行时的100多M涨到了1G多,翻了10倍。
既然知道了造成问题的原因,接下来就是从如何解决内存飚高的角度着手优化了,而这又是痛苦了好几天中最痛苦的点。
接下来,我分别从代码逻辑,调用第三方库时配置的参数,使用不到的方法实现相同的逻辑,增减容器数量,网上搜索相关帖子,请教同事等手段挨个去尝试解决方法,但都无功而返,这两天感觉自己就像是在做某个试验,组合尝试各种可能性。虽然没有找到成功的方法,但是至少知道了很多方法是不起作用的,排除了很多错误选项。而在这一次次的尝试中,最终定位在了rabbitmq接收消息的代码组件里。
然后我尝试了重写这个组件,用类封装,普通的函数都尝试了,依然不解决问题,后来我万般无奈之下把自己之前随手写的一个测试脚本放进了服务模块的代码里,这个脚本里的代码真心是毫无美感可言,但就是这样一段简简单单的代码居然成了。
有了成功的案例,那剩下的事情就好解决了,我开始对比成功的这段简易代码和之前写的更加规范的代码之间到底有何异同,最后将不同点定位在了日志模块上,后来我将更加规范的代码块中的日志模块剔除,果然内存不再飙涨,而是一直维持在容器刚初始化时候的程度,并且也达到了100%的测试要求。
最后一步,当然是解决为什么日志模块使内存上涨的原因了,查阅了众多资料后,发现是日志模块中的这段代码搞的鬼。
from concurrent_log_handler.queue import setup_logging_queues
setup_logging_queues()
这段代码的作用是,程序运行中产生的日志会先存到内存中,当达到一定量之后就会转存到磁盘里,主要目的是为了降低程序运行过程中和磁盘交互的次数,以免影响程序的性能。而我在重构的版本中需要创建好几百个不同名称的日志文件,这就造成了过多的日志都需要在内存中缓存日志信息,测试量越多,容器的内存就飙涨的越厉害,最终导致内存溢出测试中断,然后我果断减少了日志数量,内存果然不再飚高。
在挑灯夜战中度过纠结的三天,终于完美找到症结并最终破案,总算给受伤的自己带了一丝丝安慰,也希望有同样遭遇的小伙伴看到此文可以获得一些解决该问题的思路。