最近,我琢磨了一个事儿,这事儿折腾了我好久,真把我弄得哭笑不得。回头想想,那段时间,我真觉得是撞上了什么“非洲大阴阳师”在背后搞鬼,把一个简单的事情搞得乌烟瘴气,看不清摸不着。今天就来跟大家伙儿说说我是怎么把这个“大阴阳师”的秘密给揭穿的。
我真是懵圈了
事情是这样,我当时接手了一个老项目,一个有点年头、大家都不怎么愿意碰的玩意儿。项目里有个核心功能,就是导出数据报表。可怪就怪在,这个导出功能,时不时地就出问题,出什么问题?就是导出来的表格,数据老是对不上,或者干脆报错,导不出来。我们测试环境跑得好好的,一到生产环境,就跟撞了邪一样。领导也知道这个毛病,但大家都没辙,都说这个功能当初写得太糙,内部逻辑一团麻,谁也不敢动。我们组里几个经验丰富的老哥们儿,也是一摊手,摇头晃脑地说:“这个模块,祖传下来的,谁碰谁知道,跟个阴阳师作法似的,看天吃饭。”
脾气有点倔,你不让我碰,我偏要看看这“阴阳师”到底有多大的本事。于是我就开始上手琢磨这事儿。
小编温馨提醒:本站只提供游戏介绍,下载游戏请前往89游戏主站,89游戏提供真人恋爱/绅士游戏/3A单机游戏大全,点我立即前往》》》绅士游戏下载专区
我的折腾之路:从抓耳挠腮到怀疑人生
- 第一步,看日志。 我想着出错了总有迹可循?结果好家伙,生产环境的日志,那叫一个干净,一点有用的错误提示都没有,就好像什么都没发生过一样,但数据就是不对。这不就更玄乎了嘛这不是“阴阳师”是什么?
- 第二步,模拟复现。 我就想把生产环境的问题,在测试环境里重现出来。我把生产的数据倒腾到测试环境里,一遍遍地跑,各种参数都试遍了,但它就是好好的,一点毛病都没有。这一下把我搞得更郁闷了,感觉这问题就针对生产环境,简直是“专挑软柿子捏”。
- 第三步,代码走查。 硬着头皮去翻那些几年前写的代码。那代码结构,用现在的话说就是“面条代码”,从头到尾一通到底,各种判断、各种循环嵌套在一起,看得我脑壳疼。我一天恨不得盯八个小时,把那个导出模块的每一行代码都看了一遍。但我真没看出来哪里有明显的逻辑错误。
那段时间,我真是焦头烂额。晚上回到家,睡觉都梦见那些数据在表格里跳舞,就是不对劲。我开始怀疑是不是自己水平不够,是不是真的遇到什么不可思议的“系统玄学”了。
那一下,我突然就明白了
我记得那是一个周五的下午,我实在搞不明白,就坐在工位上发呆。旁边新来的小李问我:“哥,你盯着电脑屏幕,是不是在看什么电影?” 我苦笑了一下,把问题给他说了。小李听了,抓了抓头,突然说:“哥,你有没有试过,是不是生产环境的内存或者磁盘IO,跟测试环境不一样?我以前在老家一个厂子里,有台机器就这样,计算量一大就错。”
他这话一出来,我脑子里“轰”的一下,好像一道闪电劈过。我之前所有的注意力都在代码逻辑和数据本身上,完全忽略了环境差异这个最简单也最容易被忽视的问题!我的“非洲大阴阳师”作法,说不定就藏在这里面!
我赶紧去联系运维的哥们儿,问他们生产环境的配置。一问才知道,好家伙,生产环境的报表服务部署在一个虚拟机上,当时为了省钱,给分配的内存和CPU资源,就比测试环境少了一大截!而且那个虚拟机的IO也一直不稳定,在高峰期会变得特别慢。
“大阴阳师”的秘密,原来是这么回事!
这就对上了!那个导出报表的逻辑,在处理大量数据的时候,会产生临时的中间文件,而且需要大量的内存来做数据处理。
在测试环境,资源充足,处理起来顺风顺水。可到了生产环境,一旦导出数据量稍微大一点,内存就吃紧,CPU就飙升,磁盘IO就开始排队,导致什么?
- 内存不足,Java虚拟机就频繁地进行垃圾回收,导致程序卡顿,甚至因为无法分配足够的内存而强行中断。
- 磁盘IO慢,临时文件写入硬盘需要很长时间,甚至因为超时而失败。
-
最关键的,并发问题。在资源紧张的情况下,如果同时有几个用户在导出,这些问题就会被放大好几倍,最终导致数据错乱或者导出失败。而日志?因为程序不是代码逻辑上的“错误”,而是“资源不足”导致的“异常”,很多时候就直接被系统默默地中止了,根本来不及记录详细的错误日志。
这就是那个“非洲大阴阳师”的秘密!它不是什么玄学,就是生产环境资源受限和并发处理不当这两个“阴”和“阳”的问题,被当时写代码的老哥们儿忽略了,或者说,他们根本没预料到会有这么大的数据量和并发量。
我的解决办法:很简单,但很管用
找到了病根,药方就好开了。我赶紧跟领导和运维沟通,说明了情况。
我们采取了几个措施:
- 第一步,提升硬件配置。 这是最直接最有效的方法,虽然增加了成本,但一劳永逸。给报表服务所在的虚拟机,增加了内存和CPU核数,同时优化了底层存储的IO。
- 第二步,优化代码逻辑(一部分)。 我把导出模块中,那些特别吃内存和IO的地方,做了一些精简和异步处理。比如,把一些不紧急的数据处理放到了后台队列里,分批进行;减少了临时文件的生成,尽量在内存中完成处理。
- 第三步,限制并发。 既然资源有限,就不能让它“超负荷运转”。我在服务层面上加了一个简单的并发限制,比如最多同时处理X个导出请求,超出的请求就排队等待。这样至少保证了正在处理的请求能顺利完成。
这些措施一做完,你猜怎么着?那个折磨了我们组好几年的“玄学问题”,一下就烟消云散了!报表导出成功率一下子从百分之六七十,飙到了百分之九十九点九!偶尔那百分之零点一,也是网络波动或者用户自己操作失误。
现在回想起来,当初的“非洲大阴阳师”真是给我上了一课。它告诉我,很多时候,我们把问题想得太复杂,总觉得有什么高深莫测的东西在作祟,但实际上,真相往往就藏在那些最不起眼的,或者说我们习以为常的地方。多想想外部环境,多问问底层配置,可能比一头扎进代码里更能找到答案。下次再遇到这种“玄学”问题,别急着把自己变成“阴阳师”,先去把周围的环境捋一遍,说不定那“秘密”就自己蹦出来了。

