各位 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 节点经过了多次重启,实际恢复服务的时间晚了很多,这给用户造成了进一步的困扰。
mesos-slave
。(已完成)我们肩上承载着为数万开发者提供稳定服务的责任。周六傍晚事故持续的四个小时也是所有 LeanCloud 的同事最难熬的一段时间。我们了解到有的创业团队为了当天进行的一个活动,在过去的时间里非常辛苦地工作,而活动却受到了 LeanCloud 事故的影响。这样的事情让同为创业公司的我们非常地难受和惭愧。
我们希望通过这个详细的报告让用户全面地了解整个过程,并将尽一切努力降低未来发生类似事件的可能性。虽然任何人都没有办法完全保证服务中断不会发生,但我们会采取一系列措施避免可预见的问题,并确保在发生意外的时候能更快地恢复。为了保持改进过程的透明,我们开放了一个追踪各项具体措施的 Trello board,用户可以通过它随时了解我们的执行过程。
江宏
LeanCloud Cofounder/CEO
1
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 日 ------------------- 青云的这个做法挺好的 |
2
aiguozhedaodan 2015-06-08 18:18:46 +08:00
实在点:怎么补偿?
|
3
9hills 2015-06-08 18:26:16 +08:00
事故细节很详细,看来是踩了MongoDB的坑
另外资源隔离方面,用OOM优先级比较原始,可以考虑用cgroups来做限制 |
4
Jay 2015-06-08 18:45:45 +08:00
我是不敢用 MongoDB 了,还是 PostgreSQL 吧。
|
5
feisuzhu 2015-06-08 19:28:56 +08:00
@9hills
这次事故的导火索其实就是 mesos 和 docker,也就是你建议的 cgroups。(当然不是事故的原因不是 cgroups…… 我们刚刚进行了 mongo 的升级,时间规划都是精确到分钟的。都这样了,本以为对 mongo 启动恢复什么的有一定了解,然而还是踩了坑…… (真想把锅丢给 mongo 利益相关: LeanCloud 运维,目测要背锅 _(:з」∠)_ |
6
shiny 2015-06-08 19:30:19 +08:00
MongoDB 坑也踩过不少,后来就回 SQL 去了
|
7
ETiV 2015-06-08 19:35:59 +08:00 via iPhone
我用docker遇到过内核出错+母机重启,可能是艹的太猛了……
|
8
9hills 2015-06-08 19:38:18 +08:00 via iPhone
@feisuzhu 但是mesos的agent没有限制住。
现在用mesos,kubernetes,docker的越来越多了,但是这些平台本身agent的资源限制却没有。可以用简易的直接写cgroups来做限制。 |
9
9hills 2015-06-08 19:39:42 +08:00 via iPhone
@ETiV 现在cgroups还不是非常稳定,必须尽可能用最新的内核,我厂用cgroups那些kernel panic简直要疯
|
10
Livid MOD 谢谢 LeanCloud 分享踩过的坑。
|
11
feisuzhu 2015-06-08 22:31:27 +08:00
@9hills
我们没有使用 mesos 自己的 containerizer,全部都在 docker 上,没有你说的这个问题。 |
12
9hills 2015-06-08 23:02:47 +08:00 via iPhone
|
13
feisuzhu 2015-06-09 01:07:46 +08:00
|
14
xiaogui 2015-06-09 04:14:40 +08:00
后期会转为很多个独立的小集群提供服务吗?每个小集群能提供所有业务,把不同的用户分到不同的小集群中,控制每个小集群的客户量。然后在出问题的时候,只会有部分用户受到影响,不至于全部垮掉?
|
15
evlos 2015-06-09 06:15:19 +08:00
感谢分享 "架构总览" XD
|
16
phoenixlzx 2015-06-09 07:49:31 +08:00 via Android
喔....LeanCloud 也遇到 Mesos OOM 的问题了... 只不过是导致了 Mongo 一起 OOM ...
|
17
9hills 2015-06-09 08:55:03 +08:00 via iPhone
@feisuzhu mesos slave. Dockerd 自己。这些都无法被docker 托管,只能手动搞cgroups
|
18
hepochen 2015-06-09 09:38:51 +08:00
不知道读到的信息是不是误解了,有几个问题挺奇怪的:
1, 白天升级数据库?还临近流量高峰期的前几个小时,窗口期留得太自信了? 2, 一个集群内5节点,不是一个个挨个升级,而是一起来? 3, 一个集群5节点坏了,包括primary,重启其它两个节点未成功的前提下,整个集群应该是挂起的,这个时候能支撑外部的请求?如果可以支撑请求,并负载不住(远大于2/5=40%),四点到七点间,固然是高峰,但应该不是最高峰吧,那么,真正的高峰,如果所有的shard分流均衡,整个数据库的负载是多少?会不会很恐怖? Mongodb的这个集群设计,除了负载外,也是冗余的保证,2/5吃不下非真正高峰的流量,感觉不是太恰当。 4, 原先的系统就没有针对OOM(内存耗尽)的对应策略? 希望是我见识浅薄,都是误解。反之的话,哪怕一点,就没有办法让人鼓励你们了,除了佩服你们勇气之外,还剩什么呢。 |
19
hepochen 2015-06-09 09:41:45 +08:00
抱歉,我真蠢:
一个集群5节点坏了,包括primary --> 一个集群3节点坏了,包括primary |
20
feisuzhu 2015-06-09 10:00:02 +08:00
@9hills
出现问题的并不是 mesos-slave 或者 dockerd 本身,而是一个奇怪的 lsof 进程,这个进程只在部署了 mesos-slave 和 docker 的机器上出现。而且并不是 mesos-slave 或者 dockerd 的子进程,并不接受 cgroups 的监管。 |
21
feisuzhu 2015-06-09 10:00:29 +08:00
|
22
hjiang 2015-06-09 10:17:33 +08:00 via iPhone
|
23
hepochen 2015-06-09 11:29:15 +08:00
@hjiang Jiang,
其它的数据库我不知道,MongoDB的其它版本,我也不确定。 但是,2.4升级到2.6,集群内必须停机一起做?我不是你们某个员工口中的`学生`,这个要也是误解,我应该会怀疑自己做过的事情和智商了。 http://docs.mongodb.org/manual/release-notes/2.6-upgrade/#upgrade-a-replica-set-to-2-6 我觉得,你们应该遇到过单节点MongoDB故障的问题,应该也有改过甚至自己写MongoDB的drive来对应这些异常(如果没有,考虑重视),包括没有直接升到3.x,本身也很慎重,但是错了就错了,错了就是让人看笑话的,特别是你们产品这种性质的,赔笑、赔偿、赔不是,可惜你们只做到了最后一条。 算了,也不是你们的用户,真给自己找麻烦。 我应该也是误解了,特定的环境下特定的技术策略。我充其量就是半桶水的程序员而已,说的话没什么含金量。 |
24
vanemu 2015-06-09 12:02:08 +08:00
感谢分享。
我就说一点,感觉 status.leancloud.cn 不是很靠谱,目前来说,应该算是很鸡肋。因为之前是从 Parse 转过来的,比较而言 status.parse.com 就做得很好。基本上有什么故障都能及时的通知到,并且感觉也不会遗漏。status.leancloud.cn 有点摆设的意思,并且很多时候一些小的网络抖动也不会记录。 |
25
refear99 2015-06-09 13:11:49 +08:00
@LeanCloudRRY 我就想问什么事后出PHP SDK
|
26
hjiang 2015-06-09 13:36:07 +08:00 via iPhone
@hepochen 我们的 mongodb 集群不是一个简单的 replica set,而是有分片的。如果要在一个分片的集群进行在线升级,在这个过程中元数据不能发生改变,也就是说不能 创建或者删除任何 collection 或 database。但这样的操作对我们的用户来说是很常见的。如果在在线升级的漫长过程中禁用这些操作,对用户来说是不能接受的。我们评估后认为在凌晨短暂停机尽快完成升级是最好的方案,虽然要离线,但受影响的时间短很多。
我回复你想要指出的是,原帖说的故障和升级过程没有什么关系。 |
27
hjiang 2015-06-09 13:38:36 +08:00 via iPhone
@vanemu 我们现在的 status 页面确实做得不好。这次总结里其中一项要改进的就是这个页面的可靠性和准确性。
|