背景
像往常一样,和部门的同事准备参加晨会。去会议室的途中,被其他部门的同事叫住,告知收到线上告警,我们部门核心平台服务发生宕机无响应,导致他们的服务受影响。巧合的是,昨晚3大业务组熬夜到凌晨3点,联合发了一个大版本。这个时候,3个部门的同学还在家中休息。
由于是核心业务出现问题,导致影响面十分广泛。官网整站业务无法访问,用户无法进行登录操作。所有与之依赖的业务,均受到了告警。
故障处理过程
收到消息后,立刻终止了会议和运维同学一起排查故障。一边和运维同学确认服务的存活状态,一边打电话联系相关负责的同学。
首先,我们和运维同学确认了发生故障的服务器的存活状态,发现服务器并没有宕机,但是CPU略微偏高。于是,我们重启了核心服务集群。但是,情况并没有好转,服务重启后CPU很快攀升。
然后,我们立刻排查数据库的运行状态,发现数据库的CPU使用率高达95%多。并查看了一些指标,例如是否存在死锁、是否存在慢查询、会话数、CPU趋势图等。其中总会话高达900多,活跃会话有460多。于是,运维采取了删掉部分活跃会话。但是,删掉后又会产生新的会话。数据库的性能并没有得到改善。我们观察到,当前会话中,有很多重复的SQL语句。我们根据这些SQL语句的HOST来源,定位到了服务器。
根据来源地址,我们查到了服务器。为了节省资源,我们在这一台服务器上部署了多个业务(使用docker部署)。由于不能确认这个SQL来自哪个业务。于是,我们将两个业务都关闭了。然后,观察数据库的性能指标,很快数据库的CPU降下来了。我们的核心平台服务恢复了正常服务。需要解释的是,由于历史遗留原因我们核心服务与这两个次业务使用了同一个数据库。
由于关闭了两个业务服务,很快我们收到了其他BUG的反馈。于是,我们逐步恢复这两个服务。但是,恢复服务后,我们的数据库CPU再次被打满。为了不影响核心服务的使用,我们再次将两个服务关停。
随后,我们排查了我们的日志系统,观察到当前时段的流量比平常高了一倍,且有一个异常IP,异常IP平均每分钟访问次数高达4000次,高峰时达1w次/每分钟。事后,我们分析到这个异常IP的流量占据我们当时访问量的一半。我们根据这个IP进行了检索,发现这个IP正在爬取我们的公开获取用户信息的老接口。所幸的是,这个接口并没有什么隐私信息。
将IP封禁后,异常IP的访问量将下去了,但是仍有少量流量。20分钟后,流量彻底没有。于是,我们将两个次业务服务进行了恢复。
至此,所有业务的服务恢复到了正常。
原因总结
- 爬虫对接口进行了大量攻击
- 接口存在大量复杂查询且存在慢查询
- 子业务与核心业务使用同一数据库(虽然做了读写分离,但是其他数据库)
- 数据库会话数剧增,查询数量增多导致消耗增多,再加上存在慢查询最终导致CPU打满。
总结与思考
出现问题后优先做什么
出现问题后,应该思考如何快速回复服务,而不是线上debug问题。
需要意识到,服务不可用的严重性。每次的故障都会导致用户的流失,直接影响到公司的收入。应该极力避免出现故障,尽可能多的进行服务监控,及早发现问题和修复问题。
排查故障的步骤
在这次故障的修复中,一共只有两人进行故障的定位和修复。且熟悉该部分的同学均不在公司。由于缺乏经验,在排查故障中走了不少弯路。事后进行复盘,梳理了一下合理的故障排查步骤和方面:
- 根据反馈的故障,确定服务器运行指标(例如,CPU、访问量)。
- 查询数据库的指标,根据指标定位问题。例如,是否存在死锁、是否存在慢查询、会话数是否增多、是否存在异常SQL、Select 查询量、事物量占比等。
- 查询日志,是否存在异常IP访问。
- 若发现数据库存在性能问题,使用阿里云的
CloudDBA
功能,获取「问题诊断」和获取「诊断报告」。若实在不会使用,直接提交工单寻求帮助。
可以采取的优化措施
- 改造旧接口,提升接口性能
- 添加服务监控(node服务可以使用Alinode)
- 升级服务配置。核心服务进行升级配置并添加PM2,开启多进程。
- 下线掉不合理的旧接口和服务
- 在运维层,增加监控和防御。对于异常IP访问,进行限制
- 定期导出慢查询,进行优化
网友评论