对六月六日 LeanCloud 多项服务发生中断的说明

2015-06-08 18:07:08 +08:00
 LeanCloudRRY

各位 LeanCloud 的用户,大家好。

LeanCloud 的多项服务在六月六日周六下午发生了大约四个小时的中断或不稳定。其中 16:10 到 19:09 为故障阶段;19:09 到 20:17 为限流恢复阶段。

在故障阶段受到重大影响的服务包括:数据存储、网站及控制台、云代码、推送、工单系统、用户反馈、第三方登录、应用内社交;受到轻度影响的服务包括:短信、实时通信服务中获取聊天记录的 API;未受影响的服务包括:统计分析、离线数据分析、应用内搜索、文档。

在限流恢复阶段受到重大影响的服务包括数据存储、网站及控制台、云代码、推送、短信、工单系统、用户反馈、第三方登录、应用内社交、统计分析、离线数据分析、应用内搜索、文档、实时通信中获取聊天记录的 API。实时通信在这个阶段未受影响。

在这次事故中没有发生服务器端数据的丢失或损坏。

我们知道这次服务中断给很多用户造成了实质性的影响。我写这封信的目的是为了向用户说明发生的事情,以及我们将如何改进产品和服务以降低类似事件发生的可能性。

架构总览

为了更好地解释这次事故,我想先简单介绍一下 LeanCloud 的后端架构。以下是一个简化版的架构图。

虽然实际上系统间的关联比这个图要复杂,并且有一些做异步处理的系统没有画出来,但用以说明问题是足够的。

在 LeanCloud 的最前端,除了负载均衡之外就是 API 服务集群,也就是实现 RESTful API 的部分。客户端应用通过 SDK 或直接调用 API 和它通讯。根据请求的类型,API 服务再调用后端的各个系统完成所需的功能。比如如果是统计服务的请求,事件信息会被发送到统计服务并最终被保存到 HBase 集群;如果是数据存储服务的请求,那么 API 服务就会调用 MySQL 和 MongoDB 集群完成数据访问。因为 MongoDB 存储了每个应用的大部分数据,所以不少服务都需要从这里获取一些信息,是整个系统中很重要的组件。

MongoDB 集群存储了所有应用除了统计和备份数据以外的其他数据。由于数据量巨大,所以我们对 MongoDB 进行了分片(sharding),让数据分布在不同 shard。每个 shard 又由 5 台服务器(节点)组成,其中每台都保存着这个 shard 的完整数据,这样不但可以承担更高的负载,也保证了即使其中一些服务器坏掉,数据也是安全的。每个 shard 有一台称为 primary 的服务器,所有对数据的修改都会首先在这台服务器进行,然后再复制到其他服务器,而读取可以从任何一台服务器进行。当 primary 出现问题时,会有一个自动选举过程从其他成员里选出新的 primary,让服务可以继续,这是实现容错的方式。

故障说明

在故障发生前的一周,我们做了与本次故障相关的两个改动。

为了更好地管理 LeanCloud 的大量服务器,我们在近期引入了 Apache Mesos,这是一个为服务器集群的资源管理提供高层抽象接口的系统。Mesos 会在每台受管理的服务器上运行一个 mesos-slave 进程。

我们把 MongoDB 从 2.4 升级到了 2.6。新版本对地理位置的查询,以及 count 查询的准确性有所改进,所以我们认为这次升级对用户来说是值得的。但新版本的一个负面影响是,因为每次启动时要检查索引,所以启动时间大大延长了。而如果 MongoDB 是在出错的情况下重新启动,会导致大量的索引被重新建立,进一步延长启动的时间。

大约在 16:10 我们的运维工程师收到 MongoDB 集群内存不足的报警,在初步诊断后,确定原因为 mesos-slave 启动的一个子进程占用内存太多,有可能是存在内存泄漏,所以我们开始终止各台服务器的 mesos-slave 进程。在这时我们发现 MongoDB 的其中一个 shard 中有三个节点因为可用内存不足进入异常状态,其中一个是 primary,所以我们开始重启其中两个节点。由于 MongoDB 2.6 在启动过程中需要校验数据并修复索引,所以这个过程很慢,而当时正是流量高峰期,这个 shard 剩下的节点不足以承担当时的负载,所以很快被压垮。由于 primary 的连接数被占满,这导致出问题的两个节点无法加入集群。在这种情况下,我们决定屏蔽所有 API 服务请求,并重启处于错误状态的三个节点。

在此之后,这三个节点分别经历了多次重启,原因是出问题的 shard 大约有 10,000 个数据库,而新版 MongoDB 要验证每个数据库并修复索引。这不但使得重启很慢,而且因为数据库数量太多,这个过程会耗尽系统对子进程数的限制,所以在重启之后集群无法恢复正常可用状态。直到我们找到原因并调整了系统设置,各个节点才完成正常启动,集群恢复可用。

在这个过程中,除了事故本身,我们在沟通上也犯了一些错误。当用户询问服务恢复时间时,我们给出了过于乐观的估计,但因为以上所说的原因,多个 MongoDB 节点经过了多次重启,实际恢复服务的时间晚了很多,这给用户造成了进一步的困扰。

改进措施

结语

我们肩上承载着为数万开发者提供稳定服务的责任。周六傍晚事故持续的四个小时也是所有 LeanCloud 的同事最难熬的一段时间。我们了解到有的创业团队为了当天进行的一个活动,在过去的时间里非常辛苦地工作,而活动却受到了 LeanCloud 事故的影响。这样的事情让同为创业公司的我们非常地难受和惭愧。

我们希望通过这个详细的报告让用户全面地了解整个过程,并将尽一切努力降低未来发生类似事件的可能性。虽然任何人都没有办法完全保证服务中断不会发生,但我们会采取一系列措施避免可预见的问题,并确保在发生意外的时候能更快地恢复。为了保持改进过程的透明,我们开放了一个追踪各项具体措施的 Trello board,用户可以通过它随时了解我们的执行过程。

江宏

LeanCloud Cofounder/CEO

5181 次点击
所在节点    LeanCloud
31 条回复
leofml
2015-06-08 18:18:08 +08:00
你好,2015-05-18 上午 18:47 至 19:07 青云北京2区线路出现问题,经排查是 IDC 链路出口流量出现异常(受到攻击),导致部分 IDC用户(包括青云用户)出现延迟大和丢包现象。

我们对此造成的影响非常抱歉,并已根据您当时在北京2区的公网IP费用,乘以故障时间的10倍(约200分钟)予以赔付,可在充值记录页查看。

此附件 是 IDC 的故障说明,可下载阅读。如有问题,可工单与我们联系。

青云 QingCloud

2015 年 5 月 20 日


-------------------

青云的这个做法挺好的
aiguozhedaodan
2015-06-08 18:18:46 +08:00
实在点:怎么补偿?
9hills
2015-06-08 18:26:16 +08:00
事故细节很详细,看来是踩了MongoDB的坑

另外资源隔离方面,用OOM优先级比较原始,可以考虑用cgroups来做限制
Jay
2015-06-08 18:45:45 +08:00
我是不敢用 MongoDB 了,还是 PostgreSQL 吧。
feisuzhu
2015-06-08 19:28:56 +08:00
@9hills
这次事故的导火索其实就是 mesos 和 docker,也就是你建议的 cgroups。(当然不是事故的原因不是 cgroups……
我们刚刚进行了 mongo 的升级,时间规划都是精确到分钟的。都这样了,本以为对 mongo 启动恢复什么的有一定了解,然而还是踩了坑……
(真想把锅丢给 mongo

利益相关: LeanCloud 运维,目测要背锅 _(:з」∠)_
shiny
2015-06-08 19:30:19 +08:00
MongoDB 坑也踩过不少,后来就回 SQL 去了
ETiV
2015-06-08 19:35:59 +08:00
我用docker遇到过内核出错+母机重启,可能是艹的太猛了……
9hills
2015-06-08 19:38:18 +08:00
@feisuzhu 但是mesos的agent没有限制住。

现在用mesos,kubernetes,docker的越来越多了,但是这些平台本身agent的资源限制却没有。可以用简易的直接写cgroups来做限制。
9hills
2015-06-08 19:39:42 +08:00
@ETiV 现在cgroups还不是非常稳定,必须尽可能用最新的内核,我厂用cgroups那些kernel panic简直要疯
Livid
2015-06-08 20:46:47 +08:00
谢谢 LeanCloud 分享踩过的坑。
feisuzhu
2015-06-08 22:31:27 +08:00
@9hills
我们没有使用 mesos 自己的 containerizer,全部都在 docker 上,没有你说的这个问题。
9hills
2015-06-08 23:02:47 +08:00
@feisuzhu cgroups != docker

从正文看就是mesos slave占用资源超过预期,如果预先用cgroups限制住,那就没这个问题了
feisuzhu
2015-06-09 01:07:46 +08:00
@9hills
我的理解是,docker 是用 cgroups 做资源限制的(直接划等号肯定是不合适)。
所以说“预先用 cgroups 限制”实际是没有必要的,因为 docker 会帮你做。
xiaogui
2015-06-09 04:14:40 +08:00
后期会转为很多个独立的小集群提供服务吗?每个小集群能提供所有业务,把不同的用户分到不同的小集群中,控制每个小集群的客户量。然后在出问题的时候,只会有部分用户受到影响,不至于全部垮掉?
evlos
2015-06-09 06:15:19 +08:00
感谢分享 "架构总览" XD
phoenixlzx
2015-06-09 07:49:31 +08:00
喔....LeanCloud 也遇到 Mesos OOM 的问题了... 只不过是导致了 Mongo 一起 OOM ...
9hills
2015-06-09 08:55:03 +08:00
@feisuzhu mesos slave. Dockerd 自己。这些都无法被docker 托管,只能手动搞cgroups
hepochen
2015-06-09 09:38:51 +08:00
不知道读到的信息是不是误解了,有几个问题挺奇怪的:

1, 白天升级数据库?还临近流量高峰期的前几个小时,窗口期留得太自信了?

2, 一个集群内5节点,不是一个个挨个升级,而是一起来?

3, 一个集群5节点坏了,包括primary,重启其它两个节点未成功的前提下,整个集群应该是挂起的,这个时候能支撑外部的请求?如果可以支撑请求,并负载不住(远大于2/5=40%),四点到七点间,固然是高峰,但应该不是最高峰吧,那么,真正的高峰,如果所有的shard分流均衡,整个数据库的负载是多少?会不会很恐怖? Mongodb的这个集群设计,除了负载外,也是冗余的保证,2/5吃不下非真正高峰的流量,感觉不是太恰当。

4, 原先的系统就没有针对OOM(内存耗尽)的对应策略?


希望是我见识浅薄,都是误解。反之的话,哪怕一点,就没有办法让人鼓励你们了,除了佩服你们勇气之外,还剩什么呢。
hepochen
2015-06-09 09:41:45 +08:00
抱歉,我真蠢:

一个集群5节点坏了,包括primary --> 一个集群3节点坏了,包括primary
feisuzhu
2015-06-09 10:00:02 +08:00
@9hills
出现问题的并不是 mesos-slave 或者 dockerd 本身,而是一个奇怪的 lsof 进程,这个进程只在部署了 mesos-slave 和 docker 的机器上出现。而且并不是 mesos-slave 或者 dockerd 的子进程,并不接受 cgroups 的监管。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/196989

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX