文章归档

NoSQL生态系统

NoSQL 生态系统

By Jonathan Ellis,系统架构师, Translated by Jametong

空前的数据量正在驱动商业寻找传统关系型数据库的替代方案,它已经为我们服务30多年了(今年5月份ACM刚刚给关系型数据庆祝40岁生日).总体来讲,这些替代方案就是目前知名的“NoSQL数据库.”

关系型数据库的基本问题是无法处理许多现代的工作负载.有三个具体的问题领域:向外扩展(Scale out)类似于Digg(3TB的绿色徽章数据)或Facebook(50T的收件箱搜索数据)或Ebay(总共2PB的数据)的数据集,单机性能限制以及僵化的概要设计.

商业上(包含Rackspace Cloud公司)需要寻找新的方式来存储并扩展大规模的数据.我最近写了一篇关于Cassandra的文章,一个我们投入了资源的非关系型数据库.还有另外一些正在运作中的非关系型数据库,它们汇总在一起被我们称为”NoSQL运动”.

“NoSQL”这个术语实际上是由一个Rackspace的员工Eric Evans最先提出的,当时来自Last.fm网站的Johan Oskarsson提议组织一次开源分布式数据库的研讨会.这个名称与概念就一起流行了起来.

有些人反对NoSQL这个说法,因为它听起来像是仅仅表明了我们不做什么,而不是我们在做什么. 事实确实是这样,我也基本同意此说法,但是这个术语仍然有其价值,因为当关系型数据库是你所知道的唯一工具时,每个问题看起来都像个拇指(俗语,如果你手里有一个锤子,你看到什么都是钉子,译者补充).NoSQL这个术语起码让人们知道还有其他的选项可供选择.但是,当关系型数据库是解决问题的最佳工具时,我们并不是反关系型数据库者;它的涵义应该是“不仅仅有SQL(Not Only SQL)”而不是“不再有SQL(No SQL at all)”.

有关NoSQL名称的一个真实的忧虑是,它是如此大的一个概念,以致于差异巨大的设计都可以涵盖其中.如果在讨论各种产品时没有搞清楚这一点,就会导致概念混乱.因此,我建议大家沿着下面三个维度来思考这些数据库选项: 可伸缩性(scalability)、数据模型与查询模型(data and query model)以及持久化设计(persistence design).

我选择了10种NoSQL数据库作为示例.这不是一份详尽的清单,但是这里讨论的概念对于评估其他的NoSQL数据库也至关重要.

可伸缩性(Scalability)

通过使用复制, 就可以轻易扩展读的规模,因此,每当我在此文中谈到规模伸缩(scaling),都是表示通过自动分区将数据分布到多台机器以扩展写的规模.我们将做这种事情的系统称为“分布式数据库”.它们包括Cassandra、HBase、Riak、Scalaris、Voldemort以及其他很多类似的系统.如果你的写容量或写数据大小已经无法在一台机器上进行处理,如果你不想自己手工来管理分区的话,这些就是你的唯一选项了.(你不会这么做吧?)

人们使用分布式数据库主要关注两件事情: 1) 是否支持多个数据中心以及2) 能否在对应用透明的前提下往正在运行的集群中添加新机器的能力.

非分布式NoSQL数据库包括CouchDB、MongoDB、Neo4j、Redis以及Tokyo Cabinet.它们可作为分布式系统的持久层; MongoDB提供了受限制的数据分片(Sharding)功能,CouchDB也有一个独立的Lounge项目来支持做类似的分片功能,Tokyo Cabinet可用作Voldemort的存储引擎.

数据模型与查询模型

NoSQL数据库之间的数据模型与查询API千差万别.

(相关链接: Thrift, map/reduce views, Thrift, Cursor, Graph, Collection, Nested hashes, get/put, get/put, get/put)

部分重点内容介绍:

Cassandra与HBase共同使用的ColumnFamily模型都是受到Google的Bigtable论文第2节的启发. (Cassandra丢弃了历史版本,并增加了超级列(SuperColumn)的概念).在这两个系统中,都有与你之前看到的关系型数据库类似的行/列概念,但是此处的行是稀疏的行:你想要一行有多少列,一行就可以有多少列,这些列并不需要事先定义好.

键值(Key/value)模型是最简单也最容易实现的模型,但是,如果你仅想对值(Value)的一部分进行查询/更新时,它的效率会比较低.要想在一个分布式的键值上,实现更加复杂的结构也会非常困难.

文档数据库实际上是更高级的键/值(Key/Value)数据库,允许在每个键上关联嵌套的值.相对于每次简单地返回整个BLOB(二进制大对象)来讲,文档数据库支持更高效的查询.

Neo4j拥有一个非常独特的数据模型,它以节点与边的形式在图中存储对象与关系.对于适合这个模型(例如,分层数据)的查询,它的性能可能会达到其替代选项的1000倍.

Scalaris的独特之处在于,它可以提供跨越多个键的分布式事务.(关于一致性与可用性的权衡的讨论超出了本文的范围,但是,在评估分布式系统时,它也是需要记住的一方面.)

持久化设计

关于持久化设计,我的意思是“数据在内部是如何存储的?”

持久化模型可以为我们提供大量关于这些数据库适合处理多大工作负载的信息.

内存数据库非常非常快(单台机器上的Redis可以处理100,000次操作/秒),但是无法处理超过可用内存的数据集.持久性(Durability,数据不会由于服务器崩溃或停电而丢失)也是个问题; 在两次刷新到磁盘的时间间隔内预期数据丢失量可能非常大.Scalaris是我们此列表中唯一的内存数据库,它通过复制来解决持久性的问题,但是,由于它不支持跨越多个数据中心,因此,如果遇到类似电源故障一类的问题数据仍将非常脆弱.

在为了持久性写入一个仅可追加的提交日志之后,Memtable与SSTable会缓冲内存中的写操作.在接受了足够多的写操作之后(Memtable达到一定的阈值),就会对memtable中的数据进行排序,并一次性写入到磁盘,写入的文件就是一个“sstable.” 这样它就可以提供接近于内存处理的性能,因为它不涉及任何检索操作,同时又可以避免纯粹在内存中的方法那样遭遇持久性问题.(在前面引用的Bigtable论文的第5.3与5.4两节,以及论文日志结构的合并树(The Log-Structured merge-tree)中对此都有详细的描述)

几乎从有数据库开始,B-树就开始在数据库中使用了.它们提供健壮的索引支持,但是在旋转磁盘(仍然是目前最经济实用的存储介质)上, 它的性能表现比较差,因为它读写任何内容都会涉及到多次磁盘检索.

CouchDB的仅可做追加操作的B-树(Append-Only B-tree)是一个比较有趣的变体,它以限制CouchDB并发写(one write at a time)的代价避免了其检索的开销.

结论

NoSQL运动在2009年取得了爆发性的效果,因为越来越多的企业需要处理大规模的数据.Rackspace Cloud公司很高兴在NoSQL运动扮演了一个较早期的角色,还会持续为Cassandra投入资源并支持与NoSQL [...]

Cassandra - 一个分散的结构化存储系统

本文翻译自Facebook员工在LADIS大会上发布的论文.Cassandra – A Decentralized Structured Storage System
这篇论文中,两位作者详细介绍了Cassandra的系统架构,它的设计初衷,设计应用时使用到的相关技术,以及设计/实现/使用过程中得到的经验教训.

Cassandra – 一个分散的非结构化存储系统
By Avinash Lakshman Facebook ,Prashant Malik Facebook; Translated By Jametong

概要

Cassandra是一个分布式的存储系统,可用来管理分布在大量廉价服务器上的巨量结构化数据,并同时提供没有单点故障的高可用服务.Cassandra的设计目的是运行在由几百个节点(可能分布在多个不同的数据中心)组成的基础设施(infrastructure)上.当节点达到这个规模时,大大小小的组件出现故障就可能经常发生了.Cassandra在管理持久状态时面临这些故障,这种情况也驱动软件系统的可靠性(reliability)与可伸缩性(scalability)会依赖于Cassandra的服务.虽然大部分情况,Cassandra看上去像一个数据库系统, 也与数据库系统共享大量的设计与实现手段,但是Cassandra并不支持完整的关系数据模型;相反,它提供了一个简单数据模型的客户端,支持对数据布局与数据格式的动态控制.我们设计Cassandra的初衷是,可以运行在廉价硬件上,并能在不牺牲读效率的情况下实现高的写吞吐量.

1. 导论

Facebook维护着世界上最大的社交网络平台,利用分布在世界各地的大量数据中心的成千上万台服务器,为上亿的用户提供服务.Facebook平台有严格的业务要求,包含性能、可靠性、效率以及高度的可伸缩性以支持平台的持续增长.在一个包含成千上万的组件的基础设施上处理故障是我们的标准运作模式;在任何时候,随时都可能出现相当数量的服务器或网络组件故障.这样,软件系统在构建时就需要将故障当作一种常态而不是异常来处理.为了满足上面描述的这些可靠性与可伸缩性,Facebook开发了Cassandra系统.
为了实现可伸缩性与可靠性,Cassandra组合了多项众所周知的技术.我们设计Cassandra的最初目的是解决收件箱搜索的存储需要.在Facebook,这意味着这个系统需要能够处理非常大的写吞吐量,每天几十亿的写请求,随着用户数的规模而增长.由于我们是通过在地理上分布的数据中心对用户进行服务的,因此支持跨越多个数据中心的数据复制对于降低搜索延时就非常关键了.当我们在2008年6月发布收件箱搜索项目时,我们有1亿的用户,现在我们差不多有2.5亿的用户,Cassandra一直保持了其对业务的承诺.目前,Facebook内部已经有多个服务部署了Cassandra作为其后端存储系统.
本文的结构如下.第2节讨论相关研究,其中的部分研究对我们的设计有很大影响.第3节介绍详细的数据模型.第4节简要介绍客户端API.第5节介绍系统设计以及Cassandra中应用到的分布式算法.第6节介绍我们如何使用Cassandra部署Facebook平台的一个应用.

2. 相关研究

对于为了性能、可用性与数据持久性对数据进行分布,文件系统与数据库社区已经进行了广泛的研究.与仅支持扁平命名空间(namespace)的点对点(P2P)存储系统相比,分布式文件系统通常支持层次化(hierarchical)的命名空间.与Ficus[14]与Coda[16]类似的系统都是通过牺牲一致性来复制文件以实现高可用(high availability).通常使用特别的冲突解决(conflict resolution)程序来管理更新冲突(update conflict). Farsite[2]是一个没有使用任何中心服务器的分布式文件系统. Farsite使用复制来实现高可用性与可伸缩性.Google文件系统(GFS)[9]是另一个分布式文件系统,用来存储Google内部应用的各种状态数据.GFS设计比较简单,用一台主服务器存储所有的元数据(metadata),数据拆分成块(chunk)存储在多个块服务器(chunk server)上.不过,目前Google已经使用Chubby[3]抽象层为GFS的主服务器做了容错处理(fault tolerant).Bayou[18]是一个分布式的关系数据库系统,它支持断开操作(个人理解为网络断开以后的操作)并提供最终的数据一致性(eventual data consistency).在这些系统中,Bayou、Coda与Ficus允许断开操作,并且在遇到类似与网络断开与停机时能够做到自动复原.这些系统在冲突解决程序上存在差异.例如,Coda与Ficus执行系统级别的冲突解决,而Bayou允许应用级别的冲突解决.但所有这些都保证最终一致性(eventual consistency).与这些系统类似,即使在网络段开的时候,Dynamo[6]也允许进行读写操作,并使用不同的冲突解决机制(部分客户端驱动)来解决更新冲突.传统的基于复制的关系数据库系统重点在保证复制数据的强一致性(strong consistency).虽然强一致性为应用写程序提供了一个方便的编程模型,但是,这些系统在伸缩性与可用性方面却受到了限制.因为这些系统提供强一致性的保证,所以在网络分开时,它们就无法进行处理.
Dynamo[6]是一个Amazon开发的存储系统,Amazon用它来存储检索用户的购物车.Dynamo利用基于Gossip的会员算法来维护每个节点上所有其他节点的信息.可以认为Dynamo是一个只支持一跳路由请求(one-hop request routing)的结构化覆盖层(structured overlay).Dynamo使用一个向量时钟(vector lock)概要来发现更新冲突,但偏爱客户端的冲突解决机制.为了管理向量时间戳(vector timestamp),Dynamo中的写操作同时也需要执行一次读操作.在一个需要处理非常大的写吞吐量的系统中,这可能会成为瓶颈. Bigtable[4]既提供了结构化也支持数据的分布式,不过它依赖于一个分布式的文件系统来保证数据的持久化.

3. 数据模型

Cassandra中的表是一个按照主键索引的分布式多维图.它的值是一个高度结构化的对象.表中的记录键是一个没有大小限制的字符串,虽然它通常都只有16-36个字节的长度.无论需要读写多少列,单一记录键的每个副本的每次操作都是一个原子操作.多个列可以组合在一起形成一个称为column family的列的集合,这一点与Bigtable[4]系统非常相似.Cassandra提供两种类型的column family,简单的column family与超级的column family.可以将超级column family想象成column family里面嵌入column family.进一步,应用还可以指定超级column family或者简单column family里面的列的排序顺序.系统允许按时间或者名称对列进行排序.按照时间对列进行排序可以被类似于收件箱搜索这样的应用使用,因为它们的结果始终需要按照时间顺序进行展示.column family中的每个列都需要通过规范column family : column来进行访问,每个超级column family中的列都通过规范column family : super column [...]

性能与伸缩性

本文是Werner Vogels针对其”A word on Scalability“的评论所做的回应,为Scalability的定义新增了性能与运维效率等维度的说明.
关于a word on scalability的翻译可以参见此文: 简述伸缩性
本文原文链接为: Performance and Scalability

性能与伸缩性
By Werner Vogels,Translated By: Jametong

在简述伸缩性这篇文章中,我尽可能为伸缩性给出一个比它日常使用时更加精确的定义.这篇文章后面的评论以及The ServerSide的讨论中还有很多关于此定义的较好的评论.

我先以一种不太精确的方式回顾一下我给出的定义:

当我们往一个系统中新增资源时,它带来的性能提升与新增的资源量保持一定的比例关系,我们才认为此服务具备伸缩性.
对于一个永远在线的服务来讲,伸缩性意味着为促进冗余而增加的资源不会导致相应的性能损失。
一个具备伸缩性的服务需要能够处理异构的资源

有很大一部分评论认为伸缩性的定义中应该涵盖性能的维度.下面就是我如何在此情境中考虑性能维度的原因:我假设每个服务都有一个对应的SLA(Service Level Agreement,服务级别协议)合约来定义你的客户对此服务的预期.SLA中具体如何定义取决于商业需要哪种级别的服务;对于一个Amazon.com这样的网站来讲,有很大一部分服务的SLA是等待时间(latency)驱动的.这个等待时间会有一个特定的分布,你从这个分布区间中提取一个有代表性的时间来衡量你的SLA.例如,在Amazon,我们跟踪99.9%这个点上的等待时间,以确保几乎所有的客户都能取得等于或好于SLA的体验.

如果业务出现增长,这个SLA也必须得到保持.增长可能意味着请求数的增长、服务项目数量的增长、或者每次请求所需工作量的增长,如此等等.但是,不管朝着哪个方向增长, 你都需要确保总是可以满足你的SLA.系统沿着某些方向增长或许可以通过使用更快的CPU或者更大的内存以向上扩展(scale up)的方式实现,如果系统持续的增长,通过不断的购买更大更强的设备来向上扩展总会有尽头,这时你将不得不选择向外扩展(scale out).考虑到向上扩展通常更不经济,你不妨现在就开始考虑向外扩展,因为你最终将不得不走上这条路.

我很少看到纯粹吞吐量(throughput)驱动的SLA.常见的情况都是基于后续三点的一个综合,需要完成的工作量、这些工作量到达的时间分布、以及这些工作需要完成的时间点,这些情况综合起来导致了一个吞吐量驱动的SLA.等待时间也在此扮演的一个角色,因为确定需要什么样的吞吐量才能实现对应的输出分布区间,它通常都是其中的驱动因素。如果系统请求的到达分布不均匀,只要可以接受更长的等待时间,你就可以通过缓冲或设置一个低于峰值的吞吐量上限来达到目的。通常都是想要实现的这个等待时间的分布决定了吞吐量的需求。

关于伸缩性的定义还应包含哪些内容,讨论中还涉及一些其他问题,给出较好建议的人包含Gideon Low(我尝试连接到他个人的回应,但似乎做不到).

运维效率-随着硬件数量的增长,仅需要耗费较少的人力资源来管理此系统。
自修复能力-增加资源的数量也会增加这些资源中的一个出错的概率,但是出现故障的影响应该随着资源数量的增加而下降。

这两点与之前关于代价/容量/效率(cost/capacity/efficiency )的讨论一起都应该成为一个服务伸缩性定义的一部分。我将再深入思考下用什么合适的词语来表达此定义,并给出后续的建议。

简述伸缩性

本文翻译自Werner Vogels(CTO of Amazon),一篇简单的介绍伸缩性(scalability)的文章,其中涉及伸缩性的定义,以及alway-on service系统中伸缩性的定义,还涉及伸缩性可能遭遇的问题,以及如何避免这些问题的简单描述.

原文链接: A Word on Scalability

简述伸缩性
By Werner Vogels ,译者: Jametong

伸缩性是一个经常被使用的神秘咒语,用来表明某些东西设计糟糕.你可能经常会听到讨论以“但是,它无法扩展”这样一个魔咒结束争论.这通常表明,开发人员陷入了这样一种情境,他们的系统架构限制了他们的服务增长的空间。如果伸缩性以积极的面貌出现的话,它通常表达一种期望的属性“我们的平台需要好的伸缩性”。

我们认为的伸缩性到底是什么呢?当我们增加一个系统中的资源,并能获取与增加的资源保持适当的比例关系的性能提升,我们就认为这个服务具备了伸缩性。性能提升通常意味着提供更多单位的服务,但是有时它也意味着处理更大单元的工作量,比如当数据集出现增长。

在分布式系统中,还有其他理由需要增加资源到系统中;例如提高所提供服务的可靠性。引入冗余是避免故障的第一道重要防线。对于一个永远在线的服务来讲,伸缩性意味着为促进冗余而增加的资源不会导致相应的性能损失。

为什么实现伸缩性如此之难?因为伸缩性不能是一种事后的思考。它需要在应用或平台设计时就考虑其伸缩性,例如考虑增加资源确实会带来性能提升,或者引入冗余是否会给系统性能带来负面影响。很多在低负载小数据集上可以运转良好的算法,但是当请求频率增加、数据集增长或分布式系统的节点数增长的时候,其成本可能会发生爆炸性的增长。

第二个问题是,通过向外扩展的方式增长的系统通常会导致出现系统的异构性。随着新一代硬件的出现,更大或更强的资源变得越来越经济实用,或者部分资源的地理位置相距越来越远,系统中增加的资源会越来越多样化。异构性意味着部分节点将比系统中的其他节点处理的更快或者可以存储更多的数据,依赖于同质性的算法要么会在特性条件下出现崩溃,要么无法充分利用新增的资源。

实现好的伸缩性,还可能吗?完全可能,但是只有当我们在进行系统架构设计时充分考虑伸缩性时才可能实现。对于我们将要构建的系统,我们必须小心考察我们希望系统超哪个方向增长,哪些地方需要冗余,并且确保架构师明白在哪些条件下可以使用哪些工具,以及常见的陷阱都有哪些。