事件背景
作者所在的公司核心业务是做政府信息化软件的,就是为政府部门开发信息化系统。其中有一款信息化软件是客户每天需要使用的,并且他们面向的客户就是老百姓。
某年某月,某地区信息化系统,周末升级系统以后,后面连续一周,持续出现系统不稳定、宕机、服务假死、数据库锁表等事件。甚至星期五下午,出现三个多小时无法恢复系统,造成恶劣影响。
系统整体运行架构
相对传统的一个负载均衡运行架构。系统建设时间比较早(2016年),没有分布式框架,就是传统的SpringMVC+Mybatis架构,并且服务器都是基于Windows Server 2008的。
这套架构是出问题之前的架构,存在比较大的问题,在后续负载均衡章节会详细说明。
事件过程
事件持续了一周左右,出现了好几类的严重问题。
事件造成的影响
- 公司口碑受到重大影响,此次事件公司常务副总、研发中心经理、主管全部出动,去安抚客户和解决问题(系统所在地区是沿海省会级城市,面向百姓,影响比较大)。
- 出严重问题当天,刚好有督查组来访问,碰到这个事件,机构年度考核扣了好多分。
- 后续行机构收到了大量投诉,影响了很多人考评。
事件问题分析
事件一之服务假死无法访问
9.21日上午,系统出现大面积服务假死,访问长时间没有响应。服务器网络延迟也非常严重。
分析过程
- 查看服务器发现CPU异常飙高;
- 通过jstack发现大量服务在等待中(当时时间紧迫,不允许做太多的操作,要马上恢复)。直接重启了其中一台服务器上的所有服务。
- 发现没有变化,新来的请求还是直接挂起,推测不是服务的问题;
- 检查网络状态,发现服务器的网络延迟非常严重,开始怀疑是否是网络出现问题,联系网络管理员排查发现只有我们系统所在服务器出现延迟,其他服务器都正常,并且本身服务器CPU也异常,基本排除了网络引起的原因(为什么网络会大面积延迟,后面会提起);
- 马上去查看数据库监控,发现数据库CPU和IO异常(数据库由第三方公司管理,我们前期无法直接查看,联系他们以后给的监控报告)
- 通过DBA查询数据库挂起的脚本,发现有个update请求把数据库资源全部占用了,导致其他数据库请求无法进来或者响应非常慢,从而导致服务都假死了。
原因追溯
经查询,发现此次操作是一个名为更新“数据实例”功能,每次升级版本需要手动操作下此功能(情况比较复杂,无法做成自动处理)。所有的历史实例数据都会存在这个表,发生事故的时候,这张表大概有1亿3千多万的数据(Oracle比较能抗,数据量不算太大),更新实例这个功能又包含了表结构调整、索引重建、数据更新等功能(业务场景需要,原则上属于每次升级操作一次就可以),所以操作的时候会锁全表。
本来这个操作是要在系统升级完成以后操作的,但是升级的时候现场人员是新人不太熟悉情况,运行过程中客户发现数据有问题,经沟通后发现少了更新实例的操作,客户催的比较急,就直接在上线期间去操作了这个功能。因为这张表是核心表,所有业务都会走这张表的,就造成所有服务都卡死了。
后来是直接重启了数据库服务器(那时候DBA已经无法干掉进程,重启服务也失败,时间比较紧迫,经过沟通以后直接重启服务器), 之后系统恢复了,整个过程大约持续了30分钟。
解决措施
- 系统优化,原来实例表是单表,数据量后续也会越来越大,就对程序做了改造,针对这张表做了分表功能(按照时间点建立分表,程序自动处理数据,自动建立分表,相应的查询统计等都做了调整);
- 增加了权限控制,更新实例功能只允许管理员角色操作;
- 强化现场实施人员培训,哪些操作是决不允许在上线期限操作的;
因为系统所在区域的业务量还算是比较庞大的,数据积累很快,所以很久以前的一