免费下载!由 O’Reilly 出版的《NGINX 完全指南》中文版已正式上线 了解详情
写点什么

Foursquare 的 MongoDB 宕机事件

  • 2010-11-02
  • 本文字数:3224 字

    阅读完需:约 11 分钟

Foursquare 最近经历了长达 11 小时的宕机。宕机是由于他们的 MongoDB 出现了数据的不均衡增长,而这一点并没有被事先检测到。由于数据分散的原因,当 Foursquare 试图增加一个分区时没有成功,需要数据库离线才能对数据进行压缩。这也导致了系统宕机时间的延长。这篇文章提供了更多细节,记录当时发生了什么,为什么系统会宕机,Foursquare 和 10Gen 对事故的响应。

Foursquare 是一个成长极为迅速的基于位置服务的社交网络, 8 月份注册用户已经达到三百万。10 月 4 日,由于快速增长的数据,Foursquare 经历了 11 个小时的宕机。Foursquare 的运营总监 Nathan Folkman 写了一篇博客,一方面向用户道歉,一方面提供了事故发生的一些技术细节。随后10gen 的首席技术官Eliot Horowitz 写了更为详细的文章,发布到MongoDB 的用户邮件列表上。10gen 开发了MongoDB,并为Foursquare 提供技术支持。这篇分析文章引发了热议,包括Foursquare 的工程师Harry Heymann,提供了更多细节。

基础系统架构

本次受到影响的关键系统是Foursquare 的用户登入数据库。不像许多历史数据库只有小部分数据需要随时访问,10gen 的首席执行官告诉我们,“由于种种原因整个数据库被频繁访问时,会导致工作集与整个数据库的大小差不多”。因此,数据库对内存大小的需求就等于数据库中所有数据量的大小。假如数据库的大小超过了机器内存,机器性能就会出现很大的摇摆,4 块硬盘不能再负载更多的I/O 请求。对于这个的问题,他说,“被频繁访问文档,其频率远远高于你们的预期”。

最初数据库运行在一个单实例EC2 节点上,66G 内存。大约两个月之前,Foursquare 几乎耗尽了所有内存,于是他们把系统迁移到了具备两个Shard 节点的集群环境中。每个Shard 有66G 内存,为了冗余,数据被复制到Slave 节点。经过这次迁移之后,每个Shard 大概有33G 的数据。由于Shard 上的数据是“通过用户ID 平均分成200 片进行存储的”,结果就是,给定用户的所有数据会被保存在一个独立Shard 上。

宕机

由于用户持续增长,分区以一种不均衡的方式在增长,Horowitz 指出:

很容易想到会发生什么:假如某个用户子集的活跃程度高于其他人,可以想象,这些更新都是在同一个Shard 进行的。

MongoDB 会对片进行分割,每到 200M 就切分为 2 个 100M。最后的结果就是当整个系统的数据超过 116GB 时,一个分区数据是 50G,另一个会达到极限 66G,超出的请求会分散到磁盘上,性能大幅下降,从而导致系统宕机。

运营团队试图修复系统,为数据库增加了第三个 Shard,希望把系统数据的 %5 转移到新的 Shard 上,这样就和内存相匹配了。他们仅仅迁移了 5% 的数据,Horowitz 说,“我们试图迁移最少的数据,让网站尽可能快的恢复”。但是,这种方式并没有缓解整个 Shard 的性能问题。正如 Horowitz 所言:

…我们最终发现问题出在 Shard0 的碎片上。从本质上来说,虽然我们把 5% 的数据从 Shard0 上迁移到了第三个新的 Shard 上,但是数据文件,碎片状态,仍然需要占用相同数量的内存。这是因为 Foursquare 的 Check-in 文档很小(每个 300 字节),很多文档才能填满一个 4KB 的页(Page)。移走了 5% 的碎片,只是让每个页变得稀疏了一些,而不是整个删除 Page。

迁移数据的稀疏是因为数据太小了,而且由于“在 Shard 中 Key 的顺序和插入顺序是不一样的,妨碍了在连续的块中迁移数据”。为了解决性能问题,他们不得不压缩整个 Shard。目前 MongoDB 仅支持对 Shard 的离线压缩。数据的压缩,加上 EBS(Elastic Block storage)的缓慢,导致整个过程花费了 4 小时。在为 Shard 释放了 5% 的空间之后,系统终于重新上线,至此,本次宕机事故持续了整整 11 个小时。在这次突发事件里,没有数据丢失。

跟进

系统恢复之后,Foursquare 增加了多台额外的 Shard,保证分布数据的均衡。为了解决碎片问题,他们对每个 Slave 节点的分区进行压缩,然后把 Slave 节点切换为 Master 节点,再对 Master 节点进行压缩。最后每个分区使用大约 20GB 的空间。

Horowitz 表示:

10gen 团队正在实现在线增量式压缩的功能,压缩对象包括数据文件和索引。我们知道这是非 Shard 系统也会关注的功能。未来几周内会有更多详细信息。

Horowitz 指出:

需要记住的是,一旦你的系统处于最大负载,而且系统对象又非常小的情况下,就很难不停机增加更多容量。
但是,如果你能提前去做这件事,就可以在不需要停机的情况下在线为系统增加更多的 Shard。

Foursquare 小组也做出响应,承诺加强沟通,改进操作流程,如 Folkman 所言:

我们当然希望这种情况能够逐渐减少。很显然,将来当我们的系统过载时,关掉某些功能比整个系统停机要好得多。

Heymann 表示:

整体而言,我们仍然会为 Foursquare 的 MongoDB 提供大型风扇,希望能用更久一些。

社区反应

针对这篇文章,社区提出了一系列问题:

  1. Nat 问:RepairDatabase() 能否利用 CPU 的多核能力?考虑到数据已经被分割为块,是否可以进行并行处理?在互联网领域,4 小时的停机时间让人感觉太久了。

    Horowitz 答: 现在还不行。我们正在进行后台压缩功能的开发,以后就不用离线压缩了。

  2. Alex Popescu 问: 有没有真正的解决方案去处理块迁移和 Page 大小的问题?

    Horowitz 答: 是的,我们正在实现在线压缩。

  3. Suhail Doshi 问:
    我觉得最明显的问题是:如何避免 MongoDB 节点的冗余?什么时候该提供新节点?

    假定你们能监控所有事情,我们该看哪些部分?我们怎么知道呢?如果你是一家规模和功能会不断变化的公司,会发生什么情况?

    刚开始启动是似乎很难规划容量。

    Horowitz 答:
    这取决于应用系统。在某些案例中你需要把所有的索引都放在内存里,而在其他案例中可能只需要一个小工作集。

    一个好的方式是,计算出你在 10 分钟之内需要处理多少数据,索引和文档。确认可以把数据存储在内存,或者在同一时间从磁盘读取。

  4. Nat 还问了反向压力问题:“看起来当数据的增长超过内存时,性能会明显降低”。 对于该问题 Roger Binns 补充如下:

还有一些讨论,是关于固态硬盘驱动能否改善性能,但并没有确切的结论说明固态硬盘能够影响性能。还有人想知道为什么用户 ID 分区会以不均衡的方式增长。通过用户 ID 划分的分区大体上来说是均衡的──可能是有倾向性的分区(例如把旧用户放到一个 Shard 上)会导致不均衡的数据增长。

监控和未来的方向

为了更好的理解这个案例中的问题,我们采访了 10gen 的 CEO Dwight Merriman。我们问了如何更好的监控大规模部署的 MongoDB,他回答说需要依赖很多监控工具,Munin 是很常用的工具,而且它有 MongoDB 的插件。我们问道:

根据以上描述,应该能够对 MongoDB 进程使用的常驻内存进行监控,进而在 Shard 内存很低时告警,是这样吗?

假如数据库比内存大,MongoDB 会像其他数据库一样,倾向于把所有内存当作 Cache 使用。那么使用全部内存就不是什么问题。相反的情况,我们就需要知道什么时候工作集最接近内存大小。对于所有数据库来说这都很难。有一个不错的方式就是是监控其物理 I/O 的读写,并注意其增长情况。

在 Foursquare 的案例中,Merriman 同意,所有数据可以驻留在内存中,通过监控驻留内存或判断整个数据库的大小就足以预先监测问题。这就意味着,在 Shard 被用完之前,我们可以简单的定位到问题所在。事实上,无论监控是否到位,能否定位问题,好像没有人希望出现不均衡增长的情况。

我们还问到了由于这个案例的经验,10gen 是否会在开发重点上做一些改变,Merriman 的回答是他们会尽快完成后台压缩的功能。另外,Horowitz 表示 MongoDB 应该“变得更加优雅。我们会尽快完成这些增强的功能”。Merriman 指出,MongoDB 将允许对象重新集群,把非活跃的对象放入硬盘的 Page 中,而且他们相信内存映射文件会运行的很好。Horowitz 表示:

最大的问题是并发。虚拟机已经运行的很好了,问题是读写锁的粒度太粗。线程可能会引起比预期更大的故障。我们会通过以下几种方式处理这个问题:创建策略更加智能、真正的内部集合并发等。

查看英文原文: Foursquare’s MongoDB Outage

2010-11-02 00:166229

评论

发布
暂无评论
发现更多内容

Junit 测试中如何对异常进行断言

HoneyMoose

C#入门系列(七) -- 循环语句

陈言必行

C# 6月月更

Web Service进阶(五)SOAPBinding方式讲解

No Silver Bullet

6月月更 SOAPBinding

WordPress 常规设置

海拥(haiyong.site)

WordPress 6月月更

【Python技能树共建】字符串方法

梦想橡皮擦

6月月更

【100个 Unity踩坑小知识点】| Unity中的 Development build 详细解析

呆呆敲代码的小Y

【网络编程知识】什么是Socket?概念及原理分析

呆呆敲代码的小Y

Fabric.js 精简输出的JSON🎫

德育处主任

FabricJS 6月月更

重点亦难点?三个案例看数据分类分级如何有效有序进行

美创科技

数据分类 数据安全

java培训 @Autowired 的实现原理

@零度

JAVA开发

软件设计本质

GalaxyCreater

架构 设计模式 架构师 系统 软件设计

springboot,vue,es,activiti数字知识库管理系统

金陵老街

Vue springboot ES Activiti 知识库

fomo3d区块链分红游戏系统开发(案例演示)

开发微hkkf5566

性能优化手记下篇之【计费】

鲸品堂

性能优化 运维

知名巧克力全球召回,区块链帮你摆脱“甜蜜陷阱”

旺链科技

区块链 产业区块链 食品安全 食品溯源

探究Presto SQL引擎(3)-代码生成

vivo互联网技术

sql presto antlr4

微软成为规模化敏捷组织的16个关键因素

ShineScrum捷行

敏捷 谷歌 规模化敏捷

中兴新支点加入龙蜥社区,共建操作系统开源新生态

OpenAnolis小助手

开源 龙蜥社区 合作 CLA 中兴新支点

敏捷开发工具使用测评:好的敏捷项目管理工具有哪些?

PingCode

如何使用物联网低代码平台进行模型管理?

AIRIOT

物联网 低代码开发

浅谈JavaScript原型和原型链

大熊G

JavaScript 前端 6月月更

GIT 小白的指令合集

甜甜的白桃

git 版本管理 6月月更

SAP 云平台 ABAP 编程环境的前世今生

Jerry Wang

Cloud 云平台 SAP abap 6月月更

spring4.1.8初始化源码学习三部曲之一:AbstractApplicationContext构造方法

程序员欣宸

Java spring 6月月更

7 个 Flutter 开源项目,让你成为更好的 Flutter 开发者

坚果

6月月更

Linux驱动开发_视频广告机开发、Linux进程编程介绍

DS小龙哥

6月月更

AssertJ 的异常(Exception )断言

HoneyMoose

建木持续集成平台v2.4.1发布

Jianmu

DevOps CI/CD 开源项目 gitops 自动化运维

PHP开发者福音,支持CRUD代码生成且前后分离的tp6+Vue3后台管理系统开源啦!

妙码生花

php typescript Vue3 thinkphp Pinia

企业竞争利器——知识管理

小炮

Foursquare的MongoDB宕机事件_架构_Ron Bodkin_InfoQ精选文章