一次生产环境P0级事故分析( 二 )

本来想改整体业务架构的,但是发现带来的代价太大,不仅仅涉及本身系统修改,还涉及一系列供应链上系统的修改,所以就放弃了这个方案 。
事件二之Tomcat内存溢出崩溃 
9.21日下午,发现两个核心服务会不定时出现内存溢出,然后tomcat直接崩溃,9.22日下午,发现另外一个服务不定期出现tomcat内存溢出问题,同样造成tomcat崩溃
 
做过软件的都知道,虽然异常表象是一样的,但是实际产生的原因可能是完全不一样的 。
分析过程 
因为涉及到tomcat崩溃,在tomcat目录下产生了hs_err_pid.log日志,所以原因相对比较容易找,结合业务日志反查分析以后,就定位到了问题所在 。
原因追溯死循环
9.21下午出现的两个核心服务不定时出现内存溢出,查询日志发现出问题时间段内会出现大量的服务访问日志,经过追溯代码以后,发现前端的判断逻辑存在问题,会造成服务死循环访问,即A-->B,A-->B,.....
 
历史原因,部分业务逻辑代码在前端进行处理,本来服务A访问成功以后,会继续访问B服务,然后B服务访问成功以后就结束了 。但是这里的代码在特定条件下逻辑判断不严谨,会触发刷新服务,会一直重复访问A,B服务 。
模糊查询 
9.22下午出现的另外一个服务内存溢出,经过同样的分析以后,发现是一个模糊查询的请求出现异常了,正常看代码没什么问题,但是分析日志以后发现,都是一些模糊条件比较简单的请求,初步怀疑是数据没做过滤,当时数据全部加载到内存里了 。
因为分析的时候是上线期间,防止系统出现问题,没有直接抓出原请求去复现问题 。后面是让DBA,基于查询的SQL语句,去数据库日志里查询当时的执行记录,发现这几个请求平均返回的记录数都在200万以上 。至此基本上知道造成内存溢出的原因,程序里不仅仅是加载数据,还有进行数据处理的计算 。
解决措施
  • 第一个问题比较容易处理,程序修复就行,后续对这段代码逻辑重新进行了审计,最大限度排除逻辑上的缺陷 。这些情况也整理了相应的测试用例,后续纳入常规测试计划里 。
  • 第二个问题处理过程比较简单,对模糊查询做了数据量返回限制,以当时的业务场景,限制返回1000条,找不到记录再输入更精确的查询条件,并简化了代码里面的逻辑运算,大部分场景移到数据库计算(不影响整体性能) 。但是这个程序本身出现的问题其实比较低级,当时审计过程也存在问题,这种问题不应该出现
后面问过当事人,为什么要这么查询,一问发现还是我们自己的问题(设计不合理) 。这个版本上线增加了回车查询的功能,然后客户在一个词输完以后,习惯性地会敲回车,然后触发了查询,就造成了前面的事故 。比如要查询XXXX省的某个坐落门牌号,然后在输入XXXX省以后输入按了回车,就变成把全部的XXXX省数据都查询出来了 。
事后公司内部小组内也进行了案例分析,其实很多开发人员对这种问题不以为然,认为不是太大的问题,就改两句代码就行 。但是实际造成的后果可以对标互联网的P0级事故,这个带来的可不是人力成本上的损失,还有很多看不见的诸如口碑,信任等损失 。
负载均衡问题 
21号-24号中间出现几次问题,其实大部分时候都是某一台服务器上的服务出现问题,但是发现负载均衡没有发挥任何作用,服务都挂掉了,请求也一直过来 。
 
刚好周五下午也出现了更重大的事故,所以在后面就把整体策略调整了 。负载均衡设备的问题也算是为我们周五的大事故转移了一些视线吧,压力相对减轻了一些
 
原先的运行架构图
一次生产环境P0级事故分析

文章插图
 
存在的问题
  1. 负载均衡监测策略不对,只是针对端口做了类似te.NET测试,只要端口能访问就行,服务假死的时候,端口还是可以访问的,所以他认为服务还是正常的,请求照样过来 。
  2. 负载均衡访问策略也不是很合理,事故前设置的按照IP哈希的方式(经询问,原先是为了会话保持,设备的访问策略也很少,只有两三种方式),当中间一台下线,请求转到另外一台以后,后续另外一台重启起来,请求就不会过来了 。所以很多时候,监测会发现,两台服务器的压力差异非常大 。


    推荐阅读