注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Tony Woo

悠悠我梦如风逝,羁旅何日再南山。。。

 
 
 

日志

 
 

PNUTS:Yahoo!'s Hosted Data Serving Platform 中文翻译  

2012-04-07 15:16:31|  分类: NoSQL |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
PNUTS是yahoo自己提供的一个数据服务平台,在多机房布署和多点写入方面提供了一种很好的思路。所以我单独把它的一篇论文翻译出来,内容如下:


PNUTS:Yahoo!的托管数据服务平台


摘要

 
   在我们看来,PNUTS是一个Yahoo的网站应用的数据库系统,它并发量极大和分布在多个地域。PNUTS在存储方面按哈希或有序表组织数据,大量并发 地查询或更新响应时延很低,同时很有创意地为单条记录提供一致性保证。它是一个自建的、集中管理并分布在多个地域的服务,通过负载均衡和故障自动切换来降 低运营的复杂度。系统的第一个版本正在生产环境中提供服务。我们会描述PNUTS产生的起因,它的表存储和复制层的设计与实施,然后提供一些实验数据。

1、序论

    现代的网站应用在数据管理方面产生了史无前例的挑战,既便是在管理会话状态、内容元数据、用户评论和标签这类简单的任务方面也是如此。易于扩展、为分布在 不同地方的用户提供稳定而快速的响应速度以及保证高的可用性是网站应用的最重要的需求。与此同时,网站应用经常允许存在数据的不一致。我们接着详细地分析 这些需求。

扩展性

    对于象Flickr和del.icio.us这样的流行服务来说,肯定会要求数据引擎是可以扩展的。我们不仅仅是想要达到架构上的可扩展,还想要在快速增长的时候,有能力让运营人员费劲最少就能增加资源,同时增加资源时对系统的性能影响最小。

响应时间和地域分布

    始从能满足Yahoo内部服务级别协议要求的页面加载时间,这是对应用的最基本要求,这也在响应时间方面给数据管理平台提出了严格的要求。要知道网站用户 分散在全球,为了让用户快速访问服务,很有必要将数据复制到各个大陆上。考虑这些社角应用场景:印度的一所大学的毕业生会居住在北美、欧洲甚至是亚洲,某 个特定用户的数据会被他家伦敦的用户访问,同样会被他孟买和旧金山的朋友访问。数据平台既便是在面对突发的攻击流或拒绝服务攻击产生的快速变化的负载情况 下,仍然能对不同地区的用户提供快速的响应时间,如果能做到这样就比较理想了。

高可用性和容错

    Yahoo!的应用必须提供很高级别的可用性,方法是在容错的程度与出错的情况可接受的数据一致性程度上做出对应的权衡,也就是说,在出现故障的情况下, 所有应用程序仍然能够读到数据,而别的应用同时会坚持能够修改或增加数据,既便是牺牲数据的一致性也在所不惜。停机意味着失去收入。如果我们不能提供广告 服务,Yahoo!将收不到任何钱;如果我们不能展现页面内容,也会让用户失望。因而在面对服务器故障、网络分割、一个地区设施停电等各种各样的故障的情 况下也必须能继续提供服务。

放宽的一致性保证

    传统的数据库系统一直以来提供了一个在并发访问的情况实现一致性且很好理解的模型,叫作交易序列化。然而,一边是性能和可用性,另一边是数据一致性,这两 者是需要权衡的,而且不断地有人发现实现一个分布在全球范围的交易序列化的系统代价非常大。因而,在性能和可用性方面这么苛刻的情况下,对按一个序列进行 通用的事务处理变得很不实际。此外,根椐我们对许多Yahoo!应用的经验,通常也没有必要进行通用的事务处理,因为这些应用倾向于在同一时间只操作一条 记录。例如,如果用户改变头像、发布新的图像或者邀请几个朋友连上去,这个时候既便是新头像没有被一个朋友看到也没有多大害处。(尤其是这类异常很少发 生)

    既然是对通用的事务处理提供序列化效率很低同时经常也没有必要,许多分布式复制系统走到另一个极端,只提供最终的一致性保证:一个客户可以更新一个对象复 制过去的任何一个节点,而且针对一个对象的所有更新将最后都被实施,只不过在不同的节点执行的顺序很可能不一样。然而,这样一种最终一致性模型还是太弱 了,也因此对网站应用来说很不够,就象下面的一个例子所展示的:

    例1 考虑一个允许用户上传图片和设置图片访问权限的图片分享应用。为解释方便,我们假定每个用户的记录信息包含他们自己的图片列表以及允许访问各个图片的用户 列表。为了让Bob看到Alice的图片,应用程序先从数据库读取Alice的记录信息,确认Bob是不是在允许访问的列表之内,然后再根椐Bob想看的 图片列表,从对应的图片服务存储中取这些图片。一个用户希望按顺序对他自己的记录做下面两个改动:

    U1:把他的母亲从允许访问他的图片的用户列表中去掉
    U2:发一些图片

    如果采用的是最终一致性模型,U1这个更新能够发到R1这个复制节点上,而U2可能会去R2这个节点。尽管R1和R2这两个节点最后的状态是一样的(最终 一致性保证的),在R2这个节点上,有一段时间用户虽然不应该能读取,但是可以读取这个记录:图片已经发布上去,但对图片的访问控制还没有起作用。
这种异常打破了应用跟用户的协议。要知道产生这种异常的原因是R1和R2这两个节点以相反的顺序执行U1和U2这两种更新操作,也就是说,R2在过期的记录上执行上U2这个更新操作。

    正如上面这些例子所演示的那样,读取有一点点过期的数据通常是可以接受的,但是偶尔有些应用需要更强的保证。

1.1 PNUTS简介

    我们把PNUTS打造成一个超级规模、托管的数据库系统,来支持Yahoo!的网站应用。我们的焦点是为网站应用提供数据服务,而不是去支持复制的查询,如网站爬虫线下的分析。我们接着总结一下PNUTS的主要特点和一些架构上的决定。

数据模型和特点  PNUTS对用户提供简单的关系模型,支持单表扫描。其它功能包括分散聚集操作,异步通告给客户端的机制,以及批量加载机制。

容错  PNUTS在多个级别(数据、元数据,服务组件等等)上采用了冗余措施,此外依托我们的一致性模型支持读写的高可用性,既便在在发生故障或网络分割的情况下。

发布-订阅消息系统  基于主题的消息订阅与发布系统承载了异步的操作,该消息系统名叫Yahoo!消息经纪人(YMB),它跟PNUTS一起组成了Yahoo的代号叫 Sherpa的数据服务平台。我们没有使用别的异常通信协议(如流言散播协议),而是采用消息发布与订阅的主要原因是消息发布与订阅协议能为地理上分散的 多个节点做些特别优化,同时一个节点不需要知道其余节点的位置。

记录级别的主从控制  为了满足响应时间目标,PNUTS不能象在一个地区内的集群那样采用写所有数据节点的协议。然而不是每次对数据的读取都有必要读到最新的版本。我们因而选 择异步执行高时延的操作,并且支持记录级别的主从控制。同步修改分布在世界范围的多个节点需要花掉几百毫秒或更多的时间,而对一个网页访问请求来说,给数 据访问部分的时间只有50到100毫秒。异步执行让我们在地理上很分散的情况下还能满足数据访问时间的要求,而记录级别的主从允许大部分请求,包括修改操 作,访问本地区节点就能完成。

托管  PNUTS是托管的,集中管理的数据库系统,为多个应用提供服务。把数据管理作为一个服务提取出来,能有效降低应用开发的时间,因为开发人员不需要考虑与 设计自己的一套又可靠又好扩展的数据管理方案。将多个应用合并到一个服务上来,有助于分摊运营成本,并将最佳的经验用在多个应用上。除此之外,让它们共享 一个服务以让我们能够对资源(服务器,硬盘等等)进行预留,快速分配给突然很受欢迎的服务。

1.2 贡献

    在本篇论文里,我们展示了PNUT的设计、功能以及用来转发请求和协调数据快速的增长相关的关键协议与算法。为了满足网站数据平台的各项需求,我们作了不少基本的,甚至有时很激进的设计方面的决定:

. 基于记录级别的,对数据跨地区进行异步复制,使用有保证的数据传递服务而不是持久日志方式的架构。
. 一致性模型为应用提供了事务特性,但不支持事务的全序列化。
. 仔细选择了要包含的功能(哈希或有序表方式组织数据,结构灵活),或不支持的功能(限制即兴查找,没有参考完整性和事务的序列化)。
. 按托管方式提供数据管理服务

    我们会讨论这些决策,并且提供PNUTS早期的性能研究结果。我们第一个版本的系统在生产环境中使用,支持社交与广告服务。随着系统的不断完善,具备了一些额外的特性(参看第6小节),这些将被各种别的服务所使用。


2. 功能

    在本小节里我们会简单展示PNUTS的功能,指出在满足Yahoo!应用开发者关键需求情况下,使系统尽可能简单的一些限制措施。我们首先会描述一下数据和查询模型的轮廓,然后说一下一致性模型和通知模型,最后会简单讨论一下提高批量加载效率的需求。

2.1 数据与查询模型

    PNUTS为用户提供了一个简单的关系数据模型。数据放到各个表里,每个表里有不同记录,每条记录里有不同的属性。除了标准的数据类型外,blob也是有 效数据类型,在它里面允许任意的数据结构,但是不必是象图片或音频这样的大的二进制数据对象。(我们发现blob字段,完成由应用程序控制里面的逻辑,在 实践中大量应用)。记录结构是灵活的:可以随时添加新的属性,不会影响查询或更新操作,而且不要求一条记录里所有的属性必须设置对应的值。

    PNUTS查询语言支持从单一的表中进行提取和投影操作。必须指定主键才能进行更新和删除操作。虽然不如关系数据库系统,单表查询事实上比分布式哈希表或 有序数据存储更灵活,并为以后依靠系统自身进行优化提供了机会(参考3.3.1小节)。再次考虑我们假想的社交应用场景:一个用户或许更新了他自己的记 录,产生了点访问请求,别的用户或许按姓名扫描朋友的列表,产生了一段范围的访问请求。PNUTS允许应用程序自行决定表格中数据的组织方式,哈希方式或 顺序存放,有效支持上面的两种访问工作量。

    我们的系统主要是为在线应用设计的,这类应用大部分工作量是查询或更新单条记录,或小的记录组。因而,我们预期大部分扫描操作只会针对几十或几百条记录, 并为此做了对应的优化。扫描数据时可以指定在服务器端运行的判定谓词。类似地,我们提供了多记录提取操作,通过指定多个主键和可选的判定谓词从一个或多个 表中并行提取多条记录,但是再一次预期返回的记录数最多不超过几千条。
    有点遗憾,我们的系统不会强制执行类似参考完带整性方面的约束措施,尽管这可能是非常有用的。在一个有细粒度的异步执行的系统里实施上面的需求的挑战是巨 大的,很多事情留给将来去做。另外没有的功能是不提供复杂而即兴的查询(联合,分组等等)。当然,改进查询功能是将来要做的工作的一个重要方面,不过这必 须以不危及保证给更事务性网站应用请求提供的响应时间和可用性目标的的情况下去实现。在短期,我们计划为Hadoop(MapReduce的一种开源实 现)和Pig提供从PNUTS中提取数据做分析用的接口,很象MapReduce从BigTable中提取数据那样。

2.2 一致性模型:隐藏数据同步与复制的复杂细节

    PNUTS提供一个一致性模型,处于通用的事务序列化和最终一致性这两个极端之间。我们的模型起源于我们早期观察到的一个现象:网站应用非常典型地在同一 时间只操作单条记录,而不同的记录具有不同的地区活动特征。我们提供记录级别的按时间表的一致性:对一条指定的记录来说,所有节点按相同的顺序执行所有的 更新操作。在下边的图中显示了针对一条记录的更新操作序列:

PNUTS:Yahoo!的托管数据服务平台(一)



    在上面的图中,对某个特殊主键发生的事件按时间先后分别是插入、更新、更新以及删除。在插入和删除之间的时间,在图上以粗线显示,代表该记录物理存在于数 据库的时间。从任何一个节点读取数据将出返回时间线上的一个一致的版本,所有节点总是按时间线从左往右执行。这个模型的实施方法是这样的。对一条记录来 说,选择一个节点作为主节点,不同的记录的主节点是不一样的。一条记录的主节点也会随着访问方式的变化作出相应的调整,即收到大部分修改请求的节点将成为 该记录的主节点。每条记录上带一个序列号,每修改一次将会递增该序列号。就象上图所示的,序列号由记录的代数(每次新增一条记录,产生新的一代和新的代 号)和记录的版本(对记录的每次更新将产生新的版本)组成。注意到我们当前在每个节点上只保持记录的一个版本。
    通过这种记录级时间序列一致性模型,我们支持不同一致性保证的全方位的调用接口:

. 读任何版本  返回记录的一个可能过期的版本。然而不象上面的例子1,返回的是记录的修改历史中的一个有效的版本。注意这跟严格的序列化还是不一样的,因为既便是已经做 过一次成功的修改,调用这个接口时仍然可能看到一个过期的记录信息。因为这个调用的时延要比后边提到的其它具备更高一致性保证的读接口的时延低,它给应用 程序提供了一种方式,显式表明读取时关注性能胜于关注一致性。例如,在一个社交应用中显示一个朋友的状态,获得最及时的情况并不是绝对有必要,这样因而可 以调用读任何版本的这个接口。

. 读指定的版本  返回记录的指定版本,或者以后的版本。这种调用的一个典型应用场景是当用户修改记录之后想要看修改效果,需要一个反应他修过内容的版本。我们写调用接口会 返回记录改后的版本给调用者,通过调读指定的版本接口,指定版本设置成修过后刚返回的版本,读取想要的数据能够得到保证。

. 读最新的  读取最新的记录信息,包含了所有成功的修改操作。注意如果本地节点的记录信息如果太老的话,读指定的版本和读最新的请求时间会比读任何版本的调要要长,因为这个时候系统会定位并从远程的节点上取更新的版本的记录信息。

. 修改  这个调用跟单次修改事务操作一样提供相同的ACID保证。对不清楚内部结构的客户来说,这个修改调用很有用,比如用户在他自己的配置中更新他自己的状态。

. 检查并修改指定版本  这个调用只有当记录的当前版本跟调用时指定的版本一样的情况下才执行指定的修改操作。对先读记录,再根椐读取的结果去修改(如增加一个计数器的计数值)这 样的事务性修改来说,这个调用接口很有用。检查并修改指定版本能确保两个这样的并发事务能适当地序列化执行。这个调用原语是广为人知的乐观并发控制的一种 形式。

    我们的调用接口,跟SQL对比,会因透露类似序列号这样太多的实施细节而被批评。然而,透露这些细节也使得应用程序有机会放宽一致性要求而取得更高的性 能,如读取指定的版本。类似地,检查并修改指定版本也让我们在不加锁的情况进行单条记录的事务操作,在分布式系统中这是一个很受欢迎的特性。当然,如果有 需要,也可以为单条记录事务将我们的接口可以包装成传统的“开始事务”和“提交”调用,代价是失去了可表达性。注意我们的一致性保证跟传统的如序列化、可 重复读、读取已经提交的、快照隔离等等一致性保证还是不一样的。特别是我们对针对多条记录的事务不提供一致性保证。我们的模型只在单条记录的基础上提供序 列化。特别是当应用程序想在一个事务中对同一条记录读或写多次的时候,应用程序自己必须依据记录的版本取消无效的读或写操作以达成事德的序列化特性。

    在将来,我们计划为我们的一致性模型增加下面的原语:

. 捆绑式更新:为修改了多条记录的操作提供一致性保证(参考6小节)。

. 放宽的一致性:当一条记录的主节点出错,正常情况下我们的系统有对应的协议将记录切换到另一个节点上。然而如果出现重大停电故障,造成一个地区里的所有可 能包含记录主版本的机器都连接不上,这时候更新将不能在别的地区的复制节点上执行,除非显式地破坏记录的按时间序列的一致性保证。我们将允许应用程序按表 为单位指定,它们在重大的停电故障的情况是否允许执行修改操作,潜在在记录的修改上新开一个分支。如果允许执行,我们将提供自动的修改冲突解决与提醒机 制。应用程序也能从几种冲突解决机制中选取某一种,如丢弃掉某一分支,或者合并两个分支的更新等等。

2.3 通知

    类似通知这样的主动触发操作,对广告服务这样的应用很有用,这样的话当广告合同到期时它就能丢弃缓存的广告版本。类似地,我们订阅一个表的修改记录。通过我们的订阅/发布组件,很容易提供通知功能(参考3.2.1节),从而跟数据复制机制一样有严格的可靠性保证。

2.4 批量加载

    我们不光是强调扩展性,我们尽可能地想法去支持数据库系统的重要特性。批量加载工具对比较购物这样的应用很有必要,它们每天将上传大量的新的销售商品列表 到数据库里。可以将批量插入可以放到不同的存储单员上并行处理来加快加载的速度。在哈希表的情况下,哈希函数天然将插入负载分布到不同的存储单元上。然而 对于顺序存储表,批量插入按顺序排列的记录数据,这些数据需要追加到表后边或加入到已经存在的主键范围中的时候,针对这种情况需要仔细地处理避免热点同时 取得高的性能。这些情况在参考资源25中有对应的讨论。


3. 系统结构

PNUTS:Yahoo!的托管数据服务平台(一)



图1显示了PNUTS的系统结构。系统分布在多个地区,每个区包含所有系统组件以及每张表的全部数据。多区域是典型布署方式,但不是一定要分布在地理不同 的多个地区。PNUTS的一个关键特性是使用发布/订阅机制来实现数据的复制与可靠性。事实上,我们的系统并没有传统数据库日志或归档数据。相反,我们依 赖发布/订阅机制中的可靠消息传递来充当我们的重做事志,重新执行因为故障没有写到硬盘上去的更新操作。将数据复制到不同的区域提供了额外可靠性,使归档 或备份变得完成没有必要。在这一节里,我们首先讨论一个区域内组件是如何提供数据存储和提取的。然后检查我们的发布/订阅机制,Yahoo!的消息经纪 人,是如何提供可靠的数据复制与提供故障恢复作用的。之后,我们检查系统的其它方面,包括查询的处理和通知。最后,我们讨论这些是如何部署成托管的数据库 服务的。

3.1 数据存储和提取

    数据表水平分割成多个数据片,每个数据片包含多组记录。数据片分散在多台服务器上;每台服务器可能有成百上千的数据片。但是在一个区域内每个数据片只会存 在一台机器上。在我们的实施中一个典型的数据片大小在几百兆或上G字节,包含成千上万条记录。数据片可以灵活地分配到不同的服务器上,这也方便我们平衡服 务器的负载,方法是将一些数据片从过载的机器移到负载很轻的机器上。类似地,如果一台机器发生故障,将它身上的恢复出来的数据片重新分布到已有或新的机器 上,均匀地分布负载。

    图1中有三个组件主要负责对数据片进行管理和提供访问服务:存储单元、路由组件和数据片控制器。存储单元存储数据片数据,响应提取和扫描数据的请求,返回 符合条件记录,响应修改请求并执行修改操作。修改操作首先提交给消息经纪人,这在接下来的一节中介绍。存储单元可以可以使用任意合适的物理存储层。对于哈 希数据表,我们实现是采用基于UNIX文件系统的哈希表,最先由Yahoo!的用户数据库实现的。对顺序组织表,我们用mysql的InnoDB引擎,因 为它会主键值顺序保存记录。记录结构的录活性由两种存储引擎负责提供,方法是将记录存成一个JSON对象。

    为了确定一条记录由那那个存储单元负责,我们首先要确实那个数据片包含这条记录,再确定那个数据片在那个存储单元上。这两种功能都是由路由单元负责。对于 顺序记录表来说,主键的取字范围分成多个小区间,某个小区间对应一个数据片。路由单元存储内部的映射,记录了每个数据片的边界值,同时将每个数据片映射到 存储单元上。图2a是一个例子。这种映射跟B+树的一个很大的根节点类似。为了找到一个键值对应的数据片,我们按二分查找的方式去查询键对应的区别。一旦 找到数据片,我们同样也找到对应的存储单元。

PNUTS:Yahoo!的托管数据服务平台(一)



    对于按哈希组织的表,我们使用一个n位的哈希函数H(),这个函数返回的值在0与2^n-1之间。哈希空间[0...2^n)分成多个区间,每一个区间对 应一个数据片。图2b是一个例子。为了找到一个主键对应的数据片,我们运行函数取得哈希值,再按二分查找的方式找到对应的区间,也因此找到对应的数据片和 存储单元。我们选用这种机制,而没有使用传统的线性或扩展哈希机制的原因是,它跟顺序表的机制完全对等。因而我们可以用相同的代码去维护与查询按哈希方法 组织的表和顺序组织的表。

PNUTS:Yahoo!的托管数据服务平台(一)



    各个区间的映射完全放内存中,使得查询起来非常高效。例如,我们计划扩展到一个区域1000台机器的规模,每台机器存放1000个数据片。如果主键的长庆 是100个字节(这是对我们预期的应用来说最大的值了),所有的映射加在一起才用到几百兆字节的内存(每个数据片包含一个键值和存储单元的地址)。注意当 数据片的平均大小500M,这样对应的数据库达到了500T数据。对应这么大的数据库,映射可能不能全部放到内存中,我们将用一种为磁盘访问而优化过的映 谢方式。

    路由单元只是包含一份缓存过的按区间映射的版本。这种按区间映射的版本被数据片控制器所拥有,路由单元定期轮询数据片控制器去抓映射方面的修改。数据片控 制器出于负载均衡或数据恢复为目的决定移动数据片的时间,决定什么时候分割一个大的数据片。在每种情况下,数据片控制器将更新自己的权威的区间映射版本。 数据片移动或分割一小段时间后,路由单元的版本将过时,用户的请求将转会错误地转发,存储单元收到不在它服务范围的请求时给路由单元返回对应的出错信息, 这将触使路由单元从数据片控制器那取一份新的区间映射版本。因此,路由单元只有纯软状态信息;如果一个路由控制单元故障,我们简单起动一台新机器,不需要 对故障的路由单元进行数据恢复。数据片控制单元是一对主/从的机器,它不是性能的瓶颈点,因为它不在数据存储的服务路径上。

    我们系统的主要瓶颈在于存储单元的磁盘寻道容量和消息经纪人。因为这个原因,我们当前为不同的PNUTS应用分配不同的存储单元机器组和消息经纪人(最简 单的保证服务访问质量和将不同应用分开的方式)。不同应用当然可以共享路由单元和数据片控制器。在将来,我们想让所有的应用共享所有组件,这样突发的负载 高峰能够被所有可用的机器所接纳。然而,这要求我们检查灵活地配额机制和管理控制机制,以确保每种应用使用到分配给它的资源份额。

3.2 复制和一致性

    我们的系统采用异步复制来确保快速的更新响应时间。我们使用Yahoo!的消息经纪人,Yahoo!自己开发的发布/订阅系统,作为我们数据复制机制和替代重新执行日志的机制。

3.2.1 Yahoo!消息经纪人

    Yahoo!消息经纪人(YMB)是基于主题的消息发布/订阅系统,跟PNUTS一起,是Yahoo!的代号为Sherpa数据服务平台的组成部分。将数 据更新发布到YMB上后,就认为是更新已经提交。提交后某个时间点,更新将异步地传播到不同的区域,更新到对应的复制节点上。因为不同的数据复制节点可能没有执行最新的更新操作,我们需要开发一个一致性模型来帮助程序员来处理过期数据;参看2.2节。

    有两个原因使得我们能够利用YMB来做数据复制和日志记录。首先,YBM采用很多步骤来确保消息在存到数据库中去之前不会丢失。YMB保证已经发布的消息会投递到所有主题的 订阅者那,甚至在单台经纪人机器出现故障的情况下也能做到。它通过把消息记录到不同机器的不同硬盘来做到这一点的。按照我们当前的配置,初期会记录两份, 随着消息的传播将记录更多的复制份数。要等到PNUTS已经确认所有数据据复制节点已经实施了更新操作这后,对应的消息才会从YMB日志中删除掉。第二个 原因,YMB专门为广域网数据复制设计的:YMB集群分布在地理位置不同的多个数据中心,消息发布到一个YMB集群后将会被转发到别的YMB集群,并由此转给当地的消息订阅者。这种机制让不同区域的PNUTS集群不用处理更新操作在区域间的传播问题。

    YMB对发布的消息提供了偏序。发布到某个YMB集群的消息将按着发布的顺序投递到所有的订阅者。然而发布到不同的YMB集群的消息可能会以各种顺序投递 到订阅者。因而,为了提供按时间先后的一致性,我们开发了记录级别的主从机制。记录的更新由记录的主节点发布到一个YMB集群上,这样将以发布的顺序将所 有更新投递给别的数据复制节点上(请参考下一节)。当然更强的顺序保证将简化这个协议,但全局的排序对分布在不同地区的数据中心的不同消息经纪人来说实在是太昂贵了。

3.2.2 通过YMB和主从机制实现的一致性

    通过指定一个数据复制节点作为记录的主节点,把所有的更新导向这一个节点,实现记录级的按时间先后的一致性。在这样的记录级别主从机制下,主从是按记录分 配的,同一张表中不同记录的主节点会是不同的集群。我们选择这样的机制是因为我们发现在我们的网站应用中修改操作呈现很强的局部性特征。比如,通过跟踪 Yahoo!用户数据表中9.8万个用户的一周的更新情况,平均来看,对一个记录的修改85%的请求来自于同一个数据中心。这么高的局部性特征表明从性能 的角度使用主从机制是合适的。然后,不同的记录的主要的更新来源是不同的数据中心,主从的粒度必须是记录级别,不能是数据片和数据表级别;不然的话,许多 修改操作不得不花上跨区域的延迟时间到达主节点。

    所有更新通过发布到消息经纪人再传播到从节点上,并且一旦发布到消息经纪人我们就认为更新已经提交成功。记录的主节点把它的更新发布到同一个消息经纪人, 这样所有更新将按提交的顺序传递到别的数据复制节点。因为有那么多的存储单元,我们宁肯有用廉价的服务器,而不愿用昂贵可靠的专用存储。通过依靠YMB可 靠的发布特性,面对存储单元数据丢失故障我们仍然能生存下来,要知道能从远程的存储复制节点恢复所有已经提交的更新,这样我们不需要从发生故障的存储单元 哪去恢复任何数据。

    对一个记录的更新请求可能来源于一个非主节点的地区,但是它必须转发到主节点之后才算是提交成功。每条记录维护了一个隐藏的元数据,标记当前的主节点。如 果一个存储单元收到一个修改请求,它首先读取对应的记录,并确认自己是不是这条记录的主节点,不是就看应该转发请求给那个节点。记录的主节点会在不同数据 节点之间迁移。如果一个用户从威斯康星搬到加利福尼亚,系统会注意到记录的写请求主要来源变成了不同的数据中心(利用另一个隐藏的元数据记录最近N次更新 的来源),这时将发布一条YMB消息,说明这条记录的新的主节点,按照当前的配置,N等于3,另外因为我们的地区名字是2个字节,这样只对每条记录增加很 少的开销就能跟踪来源信息。

    为了强制主键限制,我们必须将插入同样的主键记录给相同的存储单元;由这个存储单元决定先插入那个,再拒绝别的请求。因而,我们针对每个数据片,选一个存 储节点作为数据片的主节点,并且将所有对某一数据片插入请求发给对应数据片的主节点。数据片主节点跟该数据片中的记录对应的主节点是不一样的。

3.2.3 故障恢复

    从别的节点上复制丢失的数据片进行故障恢复工作。复制数据片按三步进行。首先,由数据控制器从一个远程的节点(源数据片)请求一份数据。第二步,一个检查消息发布到YMB上,以便确认保任何复制开始之后进行的更新将发到源数据片上。第 三步,源数据片内容将复制到目标区域。为了支持这种恢复协议,数据片边界在不同的复制节点之间进行同步,数据片细分成小数据片操作要让所有节点在同一时间 点进行(通过在不同区域之间用两阶段提交算法实现)。在这个协议里大部分时间花在数据片从一个区域到另一个区域之间的传输上。注意在实践过程中,因为不同 区域之间传递数据的带宽开销和时延因素,有必要在靠近服务节点的地方创建备份节点。那样的话,恢复数据片时,将从附近或同一数据中心复制数据,而不是从不 同地区的数据中心去复制数据。

3.3 数据库系统的其它功能

3.3.1 查询处理

    对单条记录的读取或修改操作可以直接转发给对应数据片的存储单元。然而,操作多条记录的操作需要由一个组件来完成,由它产生多个请求并监控这些请求是否成 功或失败。负责这种操作的组件叫分散聚集引擎,并且这个是路由单元的一部分。分散聚集引擎接受针对多条记录的请求,分成多个针对单条记录或单数据片的扫描 请求,并行地发出这些请求。当请求返回,它再组装这些成功或失败的结果一起返回给客户端。在我们的实现中,这个只要有部分请求返回结果,就开始返回给客 户。我们选取服务端来负责这些种请求的做法,而不是由客户端并行发出多个请求的原因如下。首先,在TCP/IP这一层,对PNUTS服务来说,每个客户只 建一个连接是更可取的;因为有许多客户(每个客户端机器有许多并发的进程),每个客户针对每条记录都跟PNUTS并发建立一个连接的话,会加重网络协议栈 的负载。第二个原因,把这部分功能放在服务端有机会让我们进行一些优化,比如将对同一个存储单元的不同请求组织一个网站服务请求发给该存储单元。

    针对一段范围的请求和表扫描请求一样也由分散聚集引擎来处理。只有一个客户进程提取查询的结果是很典型的情况。分散聚集引擎一次只会扫描一个数据片,然后 返回数据给客户端;这也是跟标准的客户端处理数据结果的速度一样快。如果是一段范围的请求,这种机制会简化返回前多少个这类查询请求的处理(这是经常请求 的功能),因为我们只需要扫描够了满足要求的记录条数的数据片就行。返回最先的一批数据,引擎会创建并返回一个接下可以继续处理的对象,这方便客户端查询 紧接着上一个结果集后的数据集。返回的持续对象,包含一个修改过的范围请求,当再次处理时将紧接上一次返回的结果集的后边开始,这也方便在客户端保留一个 游标状态,而不是在服务端。对于象PNUTS这样的共享服务,很有必要减少为处理客户请求而在服务端保留的状态数量。

    PNUTS以后的版本将加入查询优化方面的技术,而不是这样简单的增量扫描方式。比如,如果客户端支持多个进程提取结果,我们可以并行地返回结果集,从而 利用系统天然的并发特性取得更大的吐突量。另外,如果客户端为表扫描或范围请求指定了判定谓词,我们可以扫描多个数据片以便找到少量符合条年的结果。在这 种情况下,我们维护并利用数据的统计信息,来决定大概要扫描的数据片数量,同时扫描这些数据片并返回对应的结果。

    我们有意避免支持象联合、聚合之类的复杂查询,减少意料之外的系统负载的猛增可能性。在将来,基于对系统的经验,如果用户有很强的这类需求的情况,我们可能考虑扩展查询语言,因为毕竟我们设计基础并不是不允许我们支持更丰富的查询语言。

3.3.2 通知机制

    PNUTS提供通知服务,当数据更新了主动告诉外边的系统,例如用来维护外部数据缓存或者更新搜索引擎的关键词索引。因为我们已经用了发布/订阅消息经纪 人来更新不同区域间的数据节点,提供基本的通知服务,只需要允许外部的客户能在消息经纪人那订阅更新消息并收到更新就可以。这种结构面临两个主要的挑战。 首先,在消息经纪人那每个数据片只有一个消息主题,这样外部的订阅者需要知道该订阅什么主题。然而我们不想让客户知道数据片的组织信息(这样当我们合并或 拆分数据片时不需要通知客户)。因此,我们的通知服务提供一个对一个表的所有主题的订阅机制;当拆分数据片新增一个消息主题时,客户端自动会订阅这个主 题。第二个挑战是,速度慢的客户会导致未转发的消息积压在消息经纪人那。我们当前的策略是阻止速度慢的客户订阅,当积压太多时丢弃发给他们的订阅消息。在 将来,我们计划考虑别的策略。

3.4 托管数据库服务

    PNUTS是托管式集中管理数据库服务,被多个应用共享。为了增加容量,我们增加服务器。系统会自动将一些负载转到新的机器上来适应容量的增加。对一些应 用来说瓶颈是并发的磁盘寻道次数;而对其它应用瓶颈是能用来缓存数据的内存容量或用来处理请求的CPU时间上。不管是那种情况,增加更多的服务器增加更多 的瓶颈资源。当服务器出现硬件故障(如电源烧坏了或RAID控制器故障),我们会自动将数据从别的节点上复制到别的正常运转的机器(新的或已经存在的)来 进行故障恢复工作,对故障机器只作很少或根本不做任何恢复工作。我们的目标是扩展到超过10个全球复制中心,每个中心有1000或更多的服务器。在这种规 模上,故障自动恢复和负载均衡是管理运营压力的唯一方法。

    这种托管模型产生了别的新问题,必须特别处理。首先,既便是我们相对很窄的网站服务里,不同的应用有不同的负载和需求。因此,系统必须支持几种不同的工作 负载配置,并且要能自动或简单设置成不同的配置。例如,我们的主节点迁移协议适应观察到的不同应用的修改模式。第二,我们需要分隔不同应用之间的性能影 响,这样负载很重的应用不会冲击别的应用的性能。我们当前的实施方法是,在同一区域内给不同的应用分配不同的存储单元组来达成让不同的应用不会相互影响对 方的性能的。

4. 使用PNUTS的应用

    在本小节中,我们简单描述一下推动并影响PNUTS的Yahoo!的应用。这些应用有一部分运行中PNUTS上,而这一些计划在将来运行在PNUTS上。

用户数据库  Yahoo!的用户库有几百万的活跃用户,几亿总用户。每条记录包含用户的选项、配置信息和服务使用方面的统计信息,同样也有应用相关的数据如用户邮箱主 目录位置、Yahoo!即时通讯的好友列表。在每次页面访问时会读取和可能修改这些数据,因此流量非常高。PNUTS巨大的并行能力将在支持大量的并发请 求。此外,我们的异步操作模型提供很低的响应时延,这点对于每次页页访问都需要读取或修改用户数据的情况非常关键。用户数据不能丢失,但是放宽一致性方面 的要求是可以接受的:用户自己必须看到他自己的改动,但如果别的用户在一段时间内看不到这些变化也是就可以的。因此,我们的记录级时间序列模型很适合。用 户数据库按托管的方式也工作得很好,因为许多别的应用也需要共享这些数据。

社交应用  社交应用和Web 2.0应用需要灵活的数据存储服务以支持信息的相互分享和用户之间的关系。PNUTS的记录结构灵活将支持社交应用的快速发展与升级。类似地,顺序表用来 代表社会关系图很好用。我们能建建一个用户关系表,两个朋友ID组合在一起作为主键,然后提交主键以该用户的ID开头的所有记录的范围查询请求就可以找到 该用户的所有朋友。因为这种关系数据(和别的社交信息)在不同的应用之间都有用,我们托管服务模型也很适合。社交应用会产生大量的小的更新,这种情况非常 典型,因为每次用户上传一张图片或写一篇博客都需要更新数据库。因此,有能力扩展到很高的修改比例变得很有必要,而这正是我们的并行系统能提供的。然而, 这些更新不需要实时地传播给别的用户,这意味着我们放宽的一致性模型这种应用下工作得很好。社交应用是首类在PNUTS上运行的生产应用。

内容元数据  大容量数据,如邮件附件、图片或视频的存储对Yahoo!和许多其它的网站服务公司来说都是一个不小的挑战。虽然PNUTS没有专门为大容量存储做优化, 而不提供这样的服务,但它可以作为分布式大容量存储系统的元数据存储而起到关键作用。分布式大容量存储系统保存实际的文件数据块,而PNUTS可以管理结 构化的元数据信息,这些通常情况下保存在目录和i节点上。PNUTS的客户经过仔细计划,可以用它来存放元数据,利用它的扩展能力和低时延来确保象文件创 建、重命名、修改目录等元数据操作具备很高的性能。PNUTS的一致性模型在不牺牲扩展性的情况下对合理管理元数据非常重要。

列表管理  象Yahoo!商城之样的比较购物网站会聚合各个来源的销售商品并列表显示。这种网站提供商品查询、按价格或评级进行排序等功能。我们的顺序表可以用来存 储商品列表,按时间进行排序,这样让比较购物网站提供显示最新的N个商品的功能。通过创建一个索引或数据视图(参考第6节)我们可以按象价格之样的别的属 性进行排名取出对应的数据。此外PNUTS灵活地记录结构也让它很容易为具有各种不同的属性的商品建立模型。

会话数据  网站经常需要维护每个用户的会话状态数据,对于象Yahoo!这样具有巨大数量的活跃会话网站,管理这些会话状态需要一个方便扩展的存储系统。对这些状态 信息来说,没有必要在多个地区间保持一致,应用程序可以显示式关掉PNUTS的一致性保证以获得更高的性能。在不同的应用程序之间管理用户的会话信息是一 件很复杂的工作,将会话存储服务放在PNUTS上应用程序不需要设计与实施自己的专有解决方案。


转自:http://blog.sina.com.cn/s/blog_5374d6e30100sl13.html
  评论这张
 
阅读(1109)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018