2015 年 8 月 7 日:实时通信服务宕机故障报告

8 月 7 日上午 8 点 30 分左右,聊天服务出现不稳定状态,8 点 59 分我们内部监控系统显示服务不可用并报警,工程师随之上线处理。之后陆续收到用户反馈,说终端用户无法连接上 LeanCloud 聊天服务器。经我们检查确认是由于某台服务器出现了网络故障而导致连锁反应,我们工程师在定位故障后即刻进行了服务重启和扩容,最终在 11 点 50 分让服务彻底恢复正常。

这是一次非常重大的事故。为了将问题说清楚,我们先来介绍一下 LeanCloud 聊天服务的架构。

Screen Shot 2015-08-07 at 6.21.24 PM


这里主要包括如下几部分:

  1. Router
    这是处理客户端连接请求的大门,由它来分配具体的连接服务器,客户端转而与连接服务器进行通信。
  2. 消息推送集群
    负责处理 Push Notification(消息推送)的请求。它会从消息队列里面获取请求,然后检索目标设备,最后将推送消息发送到实时通信服务器(消息推送和实时通信共享同一个长连接,如上图中 ① 所示)。
  3. 实时通信集群
    负责处理客户端的消息请求,具体而言,其内部又分为连接管理和消息发送多个模块。因为同一个应用、同一个聊天室的用户可能分散到不同物理机器上,所以在用户之间进行消息转发的时候,实时通信服务器之间会产生 RPC 调用(如上图中 ② 所示)。
  4. Zookeeper cluster
    所有集群的状态监控和自动扩展都是通过 Zookeeper 来完成。

接下来给大家还原一下事故的过程和我们的处理措施:

时间过程描述
07:57有一台服务器出现网络问题,所有进出的 RPC 请求都无法完成,与 Zookeeper 连接也多次失败。
08:25由于其他机器发送到故障机的请求堆积,整个集群内存紧张,服务开始出现不稳定。
08:59系统监控开始报警,服务大范围不可用。这时候我们工程师紧急上线开始处理。
09:10剔除故障机,第一次尝试重启集群。但由于客户端重连机制的存在,重连压力太大造成服务启动失败。
09:50用 iptables 来挡住部分连接请求,第二次尝试逐步开放服务,再次失败。
10:15扩容集群,再次逐步开放服务。虽然重连压力依然非常大,但服务器运行正常。
10:50限制对旧节点和端口的访问,开放 15% 的访问流量,这时候应用内有少量用户已经恢复使用。
11:20所有旧节点使用新端口重新上线,并逐步开放 30%、50%、70% 的访问流量。
11:50全流量开放,实时通信和推送服务完全恢复正常。

下面这张图表是我们在故障期间所监控到的连接数变化情况:

pushConnections

虽然我们较早就收到了系统报警,但在事故处置阶段,因为没有很好地应对大量客户端重连的情况,所以导致几次重新开放服务都宣告失败,影响了服务恢复的速度,这值得我们反思:当开放服务时,我们首先尝试了同时开放全部服务器,但因请求量过大,应用层无法处理而失败。然后我们将 router 规则调整为随机分配,小范围地开放了两台服务器,但又发现进程最大可用文件句柄数很快被占满,单台机器上瞬时涌入了数倍于正常状态的连接。经过分析,确认是客户端重连、发来的 SSL 握手请求无法被应用层处理,所以最后我们通过同时更改 iptables 和 router 规则,逐步放行访问流量,才让集群最终恢复过来。

本次故障持续时间超过 3 个半小时,对用户业务产生了重大影响,我们对此深感愧疚!

我们一直致力于打造最稳定的云服务,接下来整个团队会以最高优先级来解决平台稳定性问题,信誓旦旦的保证是没有实际意义的,所以后续改进措施里也加入了截止时间,希望大家一起来监督:

  1. 应用层容错:改进 RPC 容错性,限制积压请求量,避免单点故障影响全局。(预计 8 月 13 日周四完成)
  2. 问题发现速度:目前的连接波动报警机制还不及时,我们会通过短信、邮件、内部机器人等多种手段来及早报警。(预计 8 月 11 日周二完成)
  3. 事故处理速度:吸取大规模长连接集群运维经验,建立细粒度的流量控制机制,可以在系统层和应用层比较方便地进行控制。(预计到 8 月 31 日完成第一个版本)
  4. 客户端 SDK:客户端要确认在重试新的服务器前关闭旧的连接,并进一步优化重连机制。(预计 8 月 14 日周五完成)

2015 年 8 月 7 日:实时通信服务宕机故障报告》上有2条评论

  1. July

    07:57 有一台服务器出现网络问题,所有进出的 RPC 请求都无法完成,与 Zookeeper 连接也多次失败。
    08:25 由于其他机器发送到故障机的请求堆积,整个集群内存紧张,服务开始出现不稳定。

    一台主机失败了,为什么没有在集群中自动下架,集群比较忌讳的是,机器故障还在继续服务,这样会引发连锁反应
    当然看着描述好像是和 zookeeper 还能保持连接,建议设置一个阈值,在和 zookeeper 发生规定时间发生失败次数超过多少就要报警,再超过就自动下架

    回复
  2. hjc

    客户端不释放连接是个严重的 bug,每个客户端应该只同服务器建立有限的连接。可以考虑增加下发客户端重启指令或者停止重连指令的功能

    回复

发表评论

电子邮件地址不会被公开。 必填项已用*标注