Internet级单点登录的数据管理(转)

摘要
  
    Google 提供许多Internet服务,这些服务要求用户进行鉴权,依赖于一种称之为Google账号的单点登录的服务,该服务始于2002年。到2006年为止,Google在全球范围内已经拥有几十种应用,几百万用户账号。我们探讨这些服务的数据管理需求和架构、以及在运行这些服务时所遇到的问题和获得的经验。通过这些探讨,我们对“理论遇上实践”这一问题提出我们的观点。系统的成功来自于在好的算法和实际工程之间所作的折中、权衡。
  1 介绍
   Google的所有应用都基于一个常见的单点登录系统(SSO),这些应用都通过登录方式或者和增强型功能的发送来唯一识别用户。SSO的实用性则限制着这些应用的实用性。Google在实用性方面的目标是非常高的,除了他们非常熟悉的服务(例如Google Labs),因此SSO的实用性目标是具有侵略性的。在分布式系统中,为了达到较高实用性的一个方法是牺牲数据一致性。让终端用户面对不一致的逻辑数据项会使得系统走向不可预知的失败。因为Google致力于提供尽可能好的用户体验,所以他们不轻易做出权衡可用性和实用性的决定。在SSO架构设计的早期,把single-copy一致性作为可用性需求。
   在高度实用的,可容错的分布式计算机系统中获得single-copy一致性是一个值得深究的问题。Lamport's Paxos算法和Oki and Liskov的Viewstamp复制工作中的复制状态机的方法引起了我们的注意,因为这种方法具有通用性和使用性。Lampson描述了如何使用该方法和其他的机制来构建高性能的分布系统。
   因为我们考虑了Google SSO系统的多种实现方案,我们从Sleepycat Software (现在的 Oracle)的Berkeley DB(BDB-HA)研究了基于复制的高可用性的新功能。BDB-HA具有一种能兼容于Paxos and Viewstamped Replication的复制模型。它是一个嵌入式数据库,它把配置和判决规则交给应用程序处理,因此它可以很容易适用于Google的高分布性且些许非传统的产品环境。BDB数据库非常适用于具有高效率存储和检索少量随机关键值对的任务,这能很好地和SSO系统相匹配。
    接下来的内容组织如下:第2部分给出Berkeley DB实用性的背景概要;第3部分从存储的角度讨论SSO的架构,以及怎样和BDB-HA相结合。第4部分我们概括了SSO服务和BDB-HA的边界。第5部分,探讨构建和运行此系统的经验;第6部分进行总结。
  2 Berkeley DB概览
   Berkeley DB是用于值/数据对的嵌入式、高性能、可升级、事务级存储的系统。“嵌入式”表明了Berkeley DB是一个直接和应用程序的地址空间连接的库,从而避免高代价的IPC。IPC会降低客户端/服务器系统的性能。在常见的x86平台中Berkeley DB每秒能返回数以百万计的值/数据对。Berkeley DB可以升级某些数据元:它将字节存储为千兆字节;该系统可以在两个至几十个站点间进行复制;可以把它当作简单的数据仓库或者高并发性的事务级引擎。
   Berkeley DB提供键入式和有序查找。它不支持任何数据模型(例如,关联模型或者面向对象模型),但是可以在它之上使用不同的数据模型。它的简单的存储模型非常方便的为应用程序提供了存储数据的灵活性,不管是什么格式的数据。
   Berkeley DB 支持复制模型的主要复制版本,通过单一写(称之为master)和多个只读的复制版本。从概念上来说,Berkeley DB的复制是简单的:所有写操作都指向master。Master发起更新操作,接着将相应的数据库日志记录传到复制版本,每个复制版本都做出相应改变,就好像它在执行“取消操作”。复制版本在事务级的基础上执行操作,因此master忽略了的事务不需要对复制版本进行任何操作,除了写日志记录。复制版本和master一起维护同一个日志。当master发生错误时,复制版本则拥有选择权,最终“竞争胜出”的复制版本成为新的master。所有其他的复制版本则和这个新的master进行同步,根据需要回滚或者抛出它们的日志,从而保证所有的复制版本都有一致的日志。
  3 SSO架构
   图1所示为SSO的数据架构。SSO服务将用户名映射到用户帐号,将服务映射到服务所对应的数据。这些映射存储在SSO数据库中,为了平衡负载和数据定位,将它们分割为上百部分(称之为shard)。每个shard是一个复制了的Berkeley Db数据库,这个数据库由5到15个复制版本组成。每个复制版本中的SSO数据存储于单一的Berkeley DB Btree数据库中。
   较小的shard具有五个全复制版本,每一个都可以成为master。所有的更新操作都必须通过master。一致性读也必须通过master。有时候我们也允许“失效读”,相对于我们所控制的时间,失效读可能有些许过期,失效读可以执行于无master的复制版本。大的应用程序组一般具有五个能成为master的复制版本,另外还有一个只读的复制版本。只读的复制版本从master接收更新操作,但是不参与成为master的竞争,也不提交更新操作,因此,只读的复制版本的数目和它们之间的距离并不影响延迟以及操作的实用性。当系统处在良好运行状态的时候(通常情况下),只读的复制版本的状态和master同步得很好。只要多于一半的具有竞争资格的复制版本(可以成为master的复制版本)已经启动并且相互建立通信,Shard就可以拥有一个master。
   为了保证在机器、网络以及数据中心出现错误时的实用性,我们在多个分布多处的数据中心间传播复制版本。同时,我们努力保证各个复制版本间非常接近,因为复制版本间的通信延迟会影响它向shard提交写操作的时间,也会影响生成新的master的时间。为了数据定位,Shard组在地理上分布于不同位置。我们尝试着为shard指定新的用户,这种指定基于数据最可能被访问的位置。当用户数据在多个服务间共享,而且这些服务分散在不同位置的数据中心时,这种指定是明智的。现对于现在所做的,我们可以做更多的数据布局优化,但是它并不最终具有系统性能的最高优先级。
   如图1 所示,从逻辑上看,有两种不同种类的shard。绝大多数的shard是独立的数据库,它们将一组用户id映射到帐号数据,将服务id映射到独立于用户的服务数据。其他的shard则执行ID映射,将用户名映射到用户id,将用户id 映射到shard。 
     ID映射用于登录、邮件传送,有时候也用于给定用户名的用户帐号数据查询。为了客量测性,ID映射shard被链接在一个双连接的列表中,来存储可扩展的映射。链中的每个shard处理键空间的一个子列。临近的shard则储存临近的列。客户端的库代码保持ID映射中的shard名的线索以及它们相应的关键列,以使得我们不必为每个关键访问通道移动列表。如果键值在shard中恢复平衡(可以使用离线工具),存储系统的客户端会注意到相应变化并调整他们的cache定位。
  4 数据库集成
   Berkeley DB把许多判决策略放到应用程序中执行。例如,应用程序负责提供通信基础架构。应用程序注册一个回调函数,Berkeley DB在需要发送消息的时候使用该函数;应用程序则接收该消息并调用Berkeley DB函数来处理消息。因为应用程序拥有通信基础架构,所以它负责决定复制版本运行的同步程度。极端的情况下,master可以向复制版本分派消息,并假定至少有一个复制版本接收到该消息然后立即继续分派。而在另外一种极端情况下,master可以保持等待直到所有的复制版本应答表明它们已经使用发送的记录。当然,两种情况的选择会影响系统的性能和定义。
  4.1 群集
   在Paxos 和 Viewstamped Replication算法之后,Google通过执行群集协议来保证即使是在站点(包括master在内)遭遇到灾难性的数据丢失的情况下,更新的数据也不会丢失。只要Berkeley DB通知SSO应用它正在发送的信息对事务语义是必要的,那么master就一直处于等待状态,直到它从包括它本身在内的多数的复制版本那接收到确认应答。只有在接收到上述应答之后,SSO应用才会认为事务处理已经完成。因此,即使是master崩溃导致丢失它的所有数据,这些数据仍会保存在其他站点上,对事务进行应答。类似的,当要去选择一个新的master时,SSO需要得到大多数的复制版本的同意。因为任意两个复制版本是互相交迭的,所以我们可以保证至少有一个参加matser选择的复制版本可以看到来自于上一个master的最新的更新操作。Berkeley DB通常会选择一个带有最新的日志条目的复制版本作为master,所以这可以确保新的master日志将包含上一个master提交的所有更新信息。
  4.2 Lease
   一个单纯的基于Paxos的系统需要包含大量的复制版本来进行读写,这使得读操作的代价非常高。实际的系统通常应用一种称之为通话延时的机制。如果划分操作或者一些错误致使master在没有通知时间的情况下失去控制权,该机制可以允许master执行本地读操作,而避免返回旧数据的危险。
   Google在Berkeley DB复制上执行了lease机制。当回应一个读的请求时,一个master必须等待另一个master一段时间。每个lease超时周期(现在一般是几秒时间),Master通过和大部分复制版本的成功连接来刷新自己的lease。在这段暂停时间间隔期间禁止从完成了的应用中进行选择。在lease超时周期中,应用程序必须禁止master选择的完成。 lease没有必要保证适当的写行为,因为应用程序必须得到大部分复制版本的成功应答后才会认为写操作已经完成。只要master和大部分的复制版本建立连接,lease就会自动更新。
    看看master执行本地读操作时lease的必要,假设一个复制组包含5个复制版本,用A到E表示。在时间0,A是master。在时间1,网络的分隔让A在一边,从B到E则在另一边。在没有lease的情况下,从B到E的复制版本会进行一轮选择,选B为新的master,并处理新的更新操作。同时,A将继续响应本地的读请求,不知不觉就返回了旧的数据。lease机制避免从B到E的复制版本进行master的选择,直到A的master的lease期满,尽管A已经断开与其他复制版本的连接。
  4.3 群集关系
   除了群集协议和延时,复制系统的一个其他关键特性是不在Berkeley DB内处理的,它就是复制群组。
   通过改变DNS登录口来改变逻辑名从而改变这些物理环境。通过在配置重增加新的复制品名和IP地址来增加一个新的逻辑复制品。
   很难去描述一个完整的运算法则,下面给出一些关键性的概念:
   只有master执行DSN决议;
   Master的配置会随着DNS设置的改变而改变。
  配置存储在数据库里,通过一般的数据库的操作来更新。
  没有master的复制品通过检查数据库来了解配置(当前的提示告诉他们什么时候去检查)。
  配置增加或删除的部分会被列出,master定期地对它进行读取。
  鉴定性的操作(提交和选择),复制服务器只处理那些从相同配置来的信息。
  新发起的复制版本在其版本组中属于不具备竞争资格的成员.至少应在它开始运行之后,并且它被认为具有master能力它才能获得竞争资格.因此新的复制版本不能够使得竞争结果失效.
    我们要求所有的配置转换都拥有一个成员子集,这些成员属于新的或旧的集合中。这是一个比较弱化的限制,但是它可以帮助较为容易的排除同时具有多个master或者不能选出一个master的可能性。
    最通常的配置变化是根据合理的复制版本名对单一的physical machine重新布局。这应该由系统的平稳操作自动完成。其他的配置变化需要操作员进行操作。
     Paxos及其相关协议的正确性依赖于复制版本保持稳定存储。如果太多的复制版本失去状态,却继续像平常一样执行协议,并且如果其中一个复制版本是master,那么更新操作就可能会丢失。这种情况和physical replica machine的互换是相似的。只有在可以成为master的时候,失去状态的复制版本才能重新启动,作为配置中不具备竞争资格的成员。
  5 经验
  5.1 数据库和应用
   Google 使用Berkeley DB HA的第一个发行版本来开SSO的开发。Sleepycat开发了普通的基础架构,Google开发特定的应用。每一个团队都需要去做不同的权衡,我们紧密团结的工作,来决定到底因该将多种不同的功能体现在应用程序中还是Berkeley库中。
   之前关于部分群组,延时和复制版本组管理的抽象描述都是介于数据库和应用之间。例如,Google在应用中执行的master延时,是因为在那段时间内,Sleepycat无法得知从其他用户
   对这个功能发起的请求。master延时在Berkeley DB里执行,因为当master改变时,Berkeley DB有更完整和更准确的信息。接口的增加使得我们可以在应用中完成对master延时的支持,然而这并不是通常的做法。
    从竞争产生的概念上来说,Berkeley DB最初的算法和Paxos并不兼容。当一个复制版本开始一个新的竞争,它会选择一个比之前要大的生成数。对于其他复制版本来说,只有当它们没有参与过更大操作数的竞争时它们才能参与前述复制版本的竞争。为了执行Paxos-like行为,必须稳定地储存竞争生成数,以使得当所有的复制版本都关闭时(包括计划中的维护或者非计划性的断电),旧的消息仍然流动于系统中,而且在复制版本恢复之后不会在后续竞争中引起错误的行为。发生上述错误行为的可能性是很小的,但是对于像Google那么大的安装程序来说,需要尽可能地考虑更小的可能性。Sleepycat的所有其他客户都没有把这种情况当成可能的威胁。
    执行稳定的竞争id,意味着昂贵的写磁盘代价和额外的持续代价。因为在竞争过程中数据库的更新操作是无法使用的,Sleepycat希望避免竞争时的磁盘写操作,从而降低系统的整体实用性。虽然数毫秒的磁盘写等待对基于Internet的应用来说可能是可以接受的,但是在backplane-based系统中会被认为是无法可以忍受的,例如开关管理的TCP连接。两个小组对这种特性做了详细的讨论,以决定它是基础架构的要素(如Sleepycat)还是特定应用的行为(如Google所作的)。Sleepycat最终决定执行稳定的竞争生成,因为没有实质的办法在应用中正确地执行它们,还因为Sleepycat看到了Paxos全兼容执行方案的价值。
  5.2 实施
  
  经过复制的基于Berkeley DB的SSO系统使用于2003年末。从实施上来看,当我们初次将早期的SSO系统版本替换为基于Berkeley DB的未经复制的系统版本然后再替换为经过复制的版本时,事情显得非常顺利。这个系统平稳运行一个月每月后,我们就要开始考虑如何改进预期瓶颈。例如,初期配置不包含自动管理复制版本组成员资格的能力。这在大约一年后才完成,那时我们具有足够多的shard,我们的操作小组花费很多时间来人工替换出错的机器。还有一个例子,为了简单和方便,ID映射原来是由一个单一的shard来执行。大约一年后才引入可升级的ID映射,那时,流量增长的预测结果表明,现有的ID映射master将会很快超载。
  对于以合适的方法通过设置Internet服务来部署可靠的、可升级的系统来说,只有在必要的情况下延时复杂性的思想才能很好的发挥作用。有些问题必须先得到解决,否则你无法部署任何东西,而有些问题则可以稍候再解决。在最初的部署之前,当SSO系统的升级瓶颈相当不可预测时,对于系统的实际经验可以帮助我们从系统进展的角度来划分多个后续任务。这种方法用于Internet,对正在运行的软件进行完全控制,但是当产品的其他部分工作和管理时,它并不需要工作的很好。
    从操作的观点看,SSO存储系统如今具有低的维护费用,使得小组人员可以集中精力于支持新的应用和特性。从最初的部署以来,它已经经过不止一个数量级的升级;仍然有发展的空间。
  6 结论
   大型的系统需要足够的算法和较少的维护。在做设计的时候应该更多地考虑的是,系统在出现问题时怎样更好地应对,而不是考虑哪些故障会出现哪些不会出现。像Paxos具有高可容错性算法是非常有价值的。它仍然有助于了解操作环境。我们不使用byzantine容错复制算法,因为额外的成本和复杂性是不可估计的。
    需要很周详的考虑来权衡实用性和一致性。运行系统的经验让我们有理由相信在不牺牲用户体验的同时可以减轻一致性的性能要求。例如,用来标识用户的用户帐号映射几乎不改变,从shard到名字的映射也只改变一点点。我们可以允许对这些类型的稍微失时效的读操作而不牺牲可用性。然而,数据库基础设计并不支持最有效的写操作,因此我们不得不为设计中的所有写操作付出延迟和实用性的代价。
    要从整体的角度来考虑系统的实用性和可靠性,这是理所当然的教训。SSO系统由分布式的前端服务器集合,中间层服务器,负载均衡器等等,以及许多的经过复制的数据库shard组成。能够使用令人着魔的复制算法是很具有诱惑力的,这些算法详细描述系统可以多么的实用,而且具有单一副本的一致性。当这些成为重要的因素时,高实用、高可靠的数据库则成为唯一的组件;它还必须处理许多事务,如数据库组件外部的划分、依据于账户数据的服务定位,以及如何为用户层操作设置合理的超时时间。
posted on 2009-04-13 14:39  彭帅  阅读(604)  评论(0编辑  收藏  举报