Tag Archives: Shard

Foursquare 长达 11 小时的宕机

今天是个值得庆贺的日子

前几天 Foursquare 经历了长达 11 个小时的宕机,没错,11 个小时。网站官方的解释是 Shard 负载不均匀造成后续的连锁反应。很多人都知道 Foursquare 在线的 DB 是 MongoDB,今天又看到 10gen (MongoDB的开发与支持团队)的 Eliot Horowitz 在得到 Foursquare 许可后,通过邮件组详细介绍了宕机的过程:Foursquare outage post mortem,不用说,也有为 MongoDB 辟谣的意味在里面。

读罢 10gen 团队的介绍(或者说解释)之后,发现这是一个很好的研究样本。值得分享。

为了提高响应速度,Foursquare 使用 MongoDB 存储 Check-in 的数据已经有一段时间了。这部分数据的数据库起初跑在一个 66GB 内存的 Amazon EC2 单实例上(全部在内存里),两个月前,出于对容量增长的考虑,迁移到两台 Shard 集群上。每个 Shard 机器都是 66GB 内存,为了冗余,每个 Shard 都有复制到 Slave 实例。迁移的目标是所有的 Check-in 数据都保存在内存中。数据根据 ID 分成 200 个 Shard 分片,两台机器各占一半,也就说联机数据在每台机器上各使用 33GB 的内存。两个月相安无事。

问题来了,因为 Shard 算法导致的数据分散不均衡,其中一台(Shard0)数据增长到 67GB(另外一台 50GB),超过了 66GB 的限制,读写部分分散到磁盘上,性能急剧下降。从而,网站宕机。

首先尝试增加第三台 Shard 机器,上线后开始迁移,读取从三台进行,Shard0 的数据迁移到 5% 的时候,但是写操作还是让 Shard0 宕机了。这个时候发现Shard0 存在数据碎片(data fragmentation),即使数据迁移走,还是会占用原来的内存。每个Check-in 文档大约占用 300 字节,而 MongoDB 是 4KB 的页(Page),也就说十几个文档会填满一个页,而迁移 5% 反而造成了页更加稀疏,并不是将页全部删除。

这个时候已经到了第二天,随着网站全面宕机,技术团队开始用 MongoDB 的 repairDatabase() 功能来对数据库进行压缩,因为数据库太大和 EBS 慢,也因为 repairDatabase() 不能充分利用多核CPU 的能力,这个过程耗费了 4 个小时。之后这 5% 的内存空间终于释放出来,系统重新上线。

随着 Shard0 修复,第三台成功上线,进而添加了更多的 Shard 服务器,现在数据已经更加的均衡,通过在Slave上运行 repairDatabase(),然后将其切换到 Master ,每台 Shard 内存占用缩减到 20GB左右。整个故障时间已经延续了 11 小时之多。

产生问题的主要原因就是系统过载,前面介绍每台 Shard 承载原来 50% 的压力,到了问题发生的时候,单台 Shard 的负载已经超过 Shard 之前的系统负载,这时候已经积重难返了,在容量的临界点增加新系统资源,必然导致更多的停机时间。暴露了 Foursquare 团队在容量规划方面的不足之处,或许也因为业务增长太快了吧。另外,内存碎片化的问题在没有宕机之前,技术团队应该没考虑过这个问题,如果文档的大小超过 4K,碎片化问题就不严重了,这是特定应用场景造成的特定问题。10Gen 现在已经着手研究如何进在线压缩(online compaction)。再次,Shard 键值的顺序和插入顺序是不同的,这造成了迁移数据的时候 Chunk 的迁移不是连续的。

这个过程给我们的启示是:最近 NoSQL 已经成为一个热词,类似 MongoDB 这样的新事物当然值得尝试,但是不能冒进,因为驾驭起来并非易事。仅仅能够使用是不够的,系统没出问题一切都好,一旦出了异常,有足够的技术力量(设想一下 Foursquare 得不到 10gen 团队的支持会如何?) 支持么?在极端情况下如何控制? 如果回答不了这个问题,那么还应该暂缓。最好的办法就是…”等待”。

给我的另一个感慨是 Amazon 在云计算领域已经真的成为一个赢家,而且越来越得到 Web 2.0 Startup的信赖。前面说的 66GB 内存,应该指的是EC2 的 “High-Memory Double Extra Large Instance”,可提供的最大内存是 68.4 GB 。CPU 和内存能力都是可以接受的,存储方面的性能似乎还有点不足,也就是其中的 EBS ,指的是 Amazon Elastic Block storage。

EOF

开源数据库 Sharding 技术 (Share Nothing)

注:此文首发于 《程序员》杂志 2008 年 7 月刊。

从 Shard 到 Sharding

“Shard” 这个词英文的意思是”碎片”,而作为数据库相关的技术用语,似乎最早见于大型多人在线角色扮演游戏(MMORPG)中。”Sharding” 姑且称之为”分片”。

Sharding 不是一门新技术,而是一个相对简朴的软件理念。如您所知,MySQL 5 之后才有了数据表分区功能,那么在此之前,很多 MySQL 的潜在用户都对 MySQL 的扩展性有所顾虑,而是否具备分区功能就成了衡量一个数据库可扩展性与否的一个关键指标(当然不是唯一指标)。数据库扩展性是一个永恒的话题,MySQL 的推广者经常会被问到:如在单一数据库上处理应用数据捉襟见肘而需要进行分区化之类的处理,是如何办到的呢? 答案是:Sharding。

Sharding 不是一个某个特定数据库软件附属的功能,而是在具体技术细节之上的抽象处理,是水平扩展(Scale Out,亦或横向扩展、向外扩展)的解决方案,其主要目的是为突破单节点数据库服务器的 I/O 能力限制,解决数据库扩展性问题。

事关数据库扩展性

说起数据库扩展性,这是个非常大的话题。目前的商业数据都有自己的扩展性解决方案,在过去相对来说比较成熟,但是随着互联网的高速发展,不可避免的会带来一些计算模式上的演变,这样很多主流商业系统也难免暴露出一些不足之处。比如 Oracle 的 RAC 是采用共享存储机制,对于 I/O 密集型的应用,瓶颈很容易落在存储上,这样的机制决定后续扩容只能是 Scale Up(向上扩展) 类型,对于硬件成本、开发人员的要求、维护成本都相对比较高。

Sharding 基本上是针对开源数据库的扩展性解决方案,很少有听说商业数据库进行 Sharding 的。目前业界的趋势基本上是拥抱 Scale Out,逐渐从 Scale Up 中解放出来。

Sharding 的应用场景

任何技术都是在合适的场合下能发挥应有的作用。 Sharding 也一样。联机游戏、IM、BSP 都是比较适合 Sharding 的应用场景。其共性是抽象出来的数据对象之间的关联数据很小。比如IM ,每个用户如果抽象成一个数据对象,完全可以独立存储在任何一个地方,数据对象是 Share Nothing 的;再比如 Blog 服务提供商的站点内容,基本为用户生成内容(UGC),完全可以把不同的用户隔离到不同的存储集合,而对用户来说是透明的。

这个 “Share Nothing” 是从数据库集群中借用的概念,举例来说,有些类型的数据粒度之间就不是 “Share Nothing” 的,比如类似交易记录的历史表信息,如果一条记录中既包含卖家信息与买家信息,如果随着时间推移,买、卖家会分别与其它用户继续进行交易,这样不可避免的两个买卖家的信息会分布到不同的 Sharding DB 上,而这时如果针对买卖家查询,就会跨越更多的 Sharding ,开销就会比较大。

Sharding 并不是数据库扩展方案的银弹,也有其不适合的场景,比如处理事务型的应用就会非常复杂。对于跨不同DB的事务,很难保证完整性,得不偿失。所以,采用什么样的 Sharding 形式,不是生搬硬套的。

Sharding与数据库分区(Partition)的区别

有的时候,Sharding 也被近似等同于水平分区(Horizontal Partitioning),网上很多地方也用 水平分区来指代 Sharding,但我个人认为二者之间实际上还是有区别的。的确,Sharding 的思想是从分区的思想而来,但数据库分区基本上是数据对象级别的处理,比如表和索引的分区,每个子数据集上能够有不同的物理存储属性,还是单个数据库范围内的操作,而 Sharding 是能够跨数据库,甚至跨越物理机器的。(见对比表格)

Sharding.png
(转载别忘了此图。注明全文来自 https://www.dbanotes.net)

Sharding 策略

数据 Sharding 的策略与分区表的方式有很多类似的地方,有基于表、ID 范围、数据产生的时间或是SOA 下理念下的基于服务等众多方式可选择。而与传统的表分区方式不同的是,Sharding 策略和业务结合的更为紧密,成功的 Sharding 必须对自己的业务足够熟悉,进行众多可行性分析的基础上进行,”业务逻辑驱动”。

Sharding 实现案例分析:Digg 网站

作为风头正劲的 Web 2.0 网站之一的 Digg.com,虽然用户群庞大,但网站数据库数据并非海量,去年同期主数据大约只有 30GB 的样子,现在应该更大一些,但应该不会出现数量级上增长,数据库软件采用 MySQL 5.x。Digg.com的 IO 压力非常大,而且是读集中的应用(98%的 IO 是读请求)。因为提供的是新闻类服务,这类数据有其自身特点,最近时间段的数据往往是读压力最大的部分。

根据业务特点,Digg.com 根据时间范围对主要的业务数据做 Sharding,把不到 10% 的”热”数据有效隔离开来,同时对这部分数据用以更好的硬件,提供更好的用户体验。而另外 90% 的数据因用户很少访问,所以尽管访问速度稍慢一点,对用户来说,影响也很小。通过 Sharding,Digg 达到了预期效果。

现有的 Sharding 软件简介

现在 Sharding 相关的软件实现其实不少,基于数据库层、DAO 层、不同语言下也都不乏案例。限于篇幅,作一下简要的介绍。

MySQL Proxy + HSCALE

一套比较有潜力的方案。其中 MySQL Proxy (http://forge.mysql.com/wiki/MySQL_Proxy) 是用 Lua 脚本实现的,介于客户端与服务器端之间,扮演 Proxy 的角色,提供查询分析、失败接管、查询过滤、调整等功能。目前的 0.6 版本还做不到读、写分离。HSCALE 则是针对 MySQL Proxy 插件,也是用 Lua 实现的,对 Sharding 过程简化了许多。需要指出的是,MySQL Proxy 与 HSCALE 各自会带来一定的开销,但这个开销与集中式数据处理方式单条查询的开销还是要小的。

Hibernate Shards

这是 Google 技术团队贡献的项目(http://www.hibernate.org/414.html),该项目是在对 Google 财务系统数据 Sharding 过程中诞生的。因为是在框架层实现的,所以有其独特的特性:标准的 Hibernate 编程模型,会用 Hibernate 就能搞定,技术成本较低;相对弹性的 Sharding 策略以及支持虚拟 Shard 等。

Spock Proxy

这也是在实际需求中产生的一个开源项目。Spock(http://www.spock.com/)是一个人员查找的 Web 2.0 网站。通过对自己的单一 DB 进行有效 Sharding化 而产生了Spock Proxy(http://spockproxy.sourceforge.net/ ) 项目,Spock Proxy 算得上 MySQL Proxy 的一个分支,提供基于范围的 Sharding 机制。Spock 是基于 Rails 的,所以Spock Proxy 也是基于 Rails 构建,关注 RoR 的朋友不应错过这个项目。

HiveDB

上面介绍了 RoR 的实现,HiveDB (http://www.hivedb.org/)则是基于Java 的实现,另外,稍有不同的是,这个项目背后有商业公司支持。

PL/Proxy

前面几个都是针对 MySQL 的 Sharding 方案,PL/Proxy 则是针对 PostgreSQL 的,设计思想类似 Teradata 的 Hash 机制,数据存储对客户端是透明的,客户请求发送到 PL/Proxy 后,由这里分布式存储过程调用,统一分发。 PL/Proxy 的设计初衷就是在这一层充当”数据总线”的职责,所以,当数据吞吐量支撑不住的时候,只需要增加更多的 PL/Proxy 服务器即可。大名鼎鼎的 Skype 用的就是 PL/Proxy 的解决方案。

Pyshards

http://code.google.com/p/pyshards/wiki/Pyshards
这是个基于 Python的解决方案。该工具的设计目标还有个 Re-balancing 在里面,这倒是个比较激进的想法。目前只支持 MySQL 数据库。

结束语

Sharding 是一项仍处于高速发展中的”老”技术,随着 Web 2.0 的发展,Sahrding逐渐从比较”虚”的概念变成比较”实”的运用思路,开放源代码软件大潮也给 Sharding 注入新的活力,相信会有越来越多的项目采用 Sharding 技术,也会有更多成熟的 Sharding 方案和数据库附加软件涌现。

你的站点 Sharding 了么?

EOF

另,本周末我讲参加这个活动:体验基于OpenSolaris的Web/企业应用,做一个题为《设计可扩展的面向互联网应用的MySQL数据库》的简单分享。欢迎杭州朋友光临指导。

eBay 的数据层扩展经验

对于 eBay ,我盲人摸象一样写了好几篇 Blog ,暂列一下:

今天又重新读了一下这篇《The eBay Architecture –Striking a balance between site stablility, feature velocity, performance, and cost》,觉得数据层的扩展经验也很有意思。

通过功能划分不同数据库,然后根据主要访问路径水平分割数据库。这句话太空了,类似 MySQL DB 大家常采用的 Shard 思路。

减小 DB 资源开销

数据库上没有业务逻辑。这包括:不用存储过程; 只有少量比较简单的触发器。
把CPU 开销比较高的工作迁移到应用上。这包扩:参考完整性检查(嗯,检查一下你的 DB 是否再用外键? ); 连接(Join), 排序。
应用服务器尽量 Prepared 语句以及绑定变量的广泛使用。

最小化 DB 事务

自动提交(Commit)大多数主要的数据库写操作。
客户端绝对没有事务(业务逻辑) 。这包括: 单个数据库通过匿名 PL/SQL 块进行事务管理; 没有分布式事务。对于”事务”, 相关信息可以从 eBay 首席架构师 Dan Pritchett 的访谈得到确认。没有事务更没有分布式事务这一点比较关键,这也是因为 eBay 的商业逻辑天然性质(否则也不容易做),所以可以做到 Scale Out,而最近了解到 Paypal 则因为交易逻辑比较复杂,只能是 Scale Up. Paypal 的技术信息一向比较封闭,谁能告诉我一点额外的信息呢?

EOF

Digg 网站架构

digg-ready.gif

本篇描述一下 Digg 的网站架构.

国庆期间又收集了一些关于网站架构的信息。一直没有进行系统的整理。越来越发现其实都是自我重复的劳动,后续的信息都是嚼别人剩下的甘蔗。--by Fenng

Digg 工程师采用 LAMP (Linux, Apache, MySQL and PHP) 模式。这个 Alexa 排名在 100 左右的、自我估价 1.5 亿美金的站点目前有超过 100 台的 PC 服务器(足够少了),可以粗略分成三个部分:数据库服务器,Web 服务器,搜索服务器。

数据库方面,和其他成功的 Web 2.0 站点一样,也是 MySQL,不过 Digg 稍微”激进”一点,用 MySQL 5,而且号称从 MySQL 4 升级到 5 性能没有什么影响。 OLTP 应用用 InnoDB 引擎, OLAP 用 MyISAM。后端数据库的读比例达到 98%,写只有 2%,实际的读写比例应该高于这个数字,这应该是 Digg 在前端用 Memcached 以及 APC PHP accelerator / MCache 做缓存后的效果。在 IO 上似乎压力并不大。

数据库分割用 Sharding (分片)的机制。从透露出来的信息看,Digg 数据量并不大,仅仅刚超 30g . 看起来是只存储了一些元数据。至于这个 Sharding 或者 Shard, 其出发点有些类似于数据库的分区,差别可能就是不再一个库上吧,其实都是结合业务和应用来对一些数据对象进行分割。

搜索服务器用的是 Lucene

进一步阅读:

EOF