本文来自网易云社区算法
做者:王潘安网络
如下是本人在学习Google的Mesa数据仓库论文的记录,翻译出来给你们分享,翻译水平有限,请多多包涵。因论文比较长,本人将论文按照Mesa不一样的模块分开翻译,方便阅读。架构
摘要:Mesa是一个可伸缩性的分析型数据仓库系统,它主要为Google的互联网广告业务服务。Mesa的设计是为了知足一系列的来自用户和系统的复杂的挑战。包括近乎实时的数据获取和查询,高可用性,可靠性,容错性以及伸缩性。Mesa每秒处理PB级的数据以及百万行的更新。天天服务十亿次查询,获取万亿行数据。Mesa是一个跨多个数据中心的数据仓库,它提供一致的,可重复,低延迟的查询服务,即便是在一个数据中心彻底瘫痪的状况下。并发
一.介绍异步
随着业务量的增大,数据的处理,存储和查询都面临挑战。对数据存储的要求有以下几点(此处省略一堆废话):分布式
原子更新。一个单用户的操做就可能引发相关数据的屡次更新,影响大量的定义在跨多维度上的多指标集的一致性视图。不容许存在对系统进行查询时,只有一部分数据更新成功的状况。函数
一致性和正确性。出于商业和法律上的考虑。系统必须返回一致和正确的数据。即便一个查询跨多个数据中心,咱们也要提供强一致性和可重复的查询结果。性能
可用性。系统不容许出现单点故障。不会出现因为计划中或非计划中的维护或故障所形成的停机,即便出现影响整个数据中心或地域性的断电也不能形成停机。 近实时的更新。系统必须支持大约每秒几百万行规模的持续更新,包括添加新数据行和对现有数据行的增量更新。这些更新必须在几分钟内对跨不一样视图和数据中心的查询可见。 查询性能。系统必须对那些对时间延迟敏感的用户提供支持,按照超低延迟的要求为他们提供实时的客户报表,而进行批处理的用户须要很是高的吞吐量。总的来讲,系统必须支持将99%的点查询的延迟控制在数百毫秒以内,而且总体查询控制在天天获取万亿行的吞吐量。
可伸缩性。系统规模必须能够随着数据规模和查询总量的增加而伸展。举个例子,它必须支持万亿行规模和PB级的数据。可是即便上述参数再出现显著增加,更新和查询的性能必须仍然得以保持。学习
在线的数据和元数据转换。为了支持新功能的发布或对现有数据粒度的变动,客户端常常须要对数据模式进行转换或对现有数据的值进行修改。这些变动必须对正常的查询和更新操做没有干扰。大数据
Mesa是针对这些技术上和操做上的挑战的解决方案。尽管这些需求的某一部分已经被现有的数据仓库系统解决了。Mesa是一个能同时解决上述问题的解决方案。Mesa是一个针对结构化数据的分布式,可备份而且高可用的数据处理,存储和查询系统。Mesa从生成数据的流服务中获取数据,在内部进行聚合和持久化,经过查询给用户提供服务。尽管这篇论文主要讨论的是广告业务,可是Mesa是一个能知足上述全部需求的通用的数据仓库。
Mesa利用谷歌的基础设施和服务,好比Colossus(谷歌下一代的分布式文件系统),BigTable以及MapReduce,将数据被水平分片和备份,来实现存储的可扩展性和可用性。更新操做可能会发生在一个单表的粒度上或者跨多张表。为了实现一致性以及知足在更新的时候的反复查询,基础数据是多版本的。为了实现数据更新的可扩展性,数据是批量的,带版本号的,周期性的合并进入Mesa中的。为了实现跨多数据中心的更新一致性,Mesa使用基于Paxos的分布式一致性协议。
许多基于关系型和数据立方体的数据仓库产品不支持在给用户提供近实时查询的同时,每几分钟就将数据仓库中的数据连续的集成和汇聚。一般,这些解决方法都是与传统企业数据仓库相关的。在传统企业数据仓库中,数据汇聚进入数据仓库的频率低,一般是按天或者周汇聚。相似的,谷歌内部的关于大数据的技术,好比说BigTable, Megastore, Spanner和F1,也都不能知足这个场景。BigTable不能知足Mesa提出的必要的原子性的需求。Megastore, Spanner和F1一般用来处理线上业务,他们支持跨地域的数据的强一致性,可是它们不能知足Mesa更新操做吞吐量的峰值。可是,Mesa确实使用了BigTable和Paxos技术以及Spanner的元数据存储的技术。
(这段实在不想翻译了。总之,目前市面上的大数据产品都不行!真是狂拽酷炫吊炸天!)
这篇论文的贡献主要以下:
咱们展现了如何建立一个PB级数据仓库,同时又拥有ACID这些事物性处理功能的系统。而且它可伸缩,来知足谷歌高吞吐率的广告指标。
咱们描述了一个版本管理系统,它使得高吞吐量的批量更新操做在可接受的延迟内完成,同时也支持大量的查询在低延迟下完成。
咱们描述了一个高扩展性的分布式架构,在单数据中心中,它能够从宕机和网络故障中恢复。咱们也展现了一个跨地域备份的架构来应对数据中心的瘫痪。这种设计的不一样之处在于,业务数据是经过独立且冗余的进程在多数据中心间异步备份。只有关键的元数据是同步的拷贝到每一个地方。这种技术可使跨数据中心的同步代价最小,而且还能够提供高吞吐的更新操做。
咱们展现了如何在不影响正确性和已存在应用的性能的条件下,动态和高效的处理大量表模型的变化。
咱们描述了应对由硬件或者软件引发的数据错误的关键技术。
咱们描述了这种规模的系统在保证正确性,一致性和性能上的挑战。而且提出几点供新的研究来改进。
二 . Mesa存储子系统
Mesa中的数据持续不断的生成,它是谷歌量级最大,价值最高的数据集。在这个数据集上的分析型查询包括简单的查询,诸如:“某一个特定的广告在某一天有多少点击量?”和涉及更多内容的查询,诸如:“某一个特定的广告,在十月份第一个星期的上午8点到11点间,经过移动设备在某个特定的地理位置,经过关键字decaf在google.com上搜索得到的点击量是多少?”
数据在Mesa中以多维模型存放,它依据不一样的维度获取了全部谷歌广告平台上最细节的事实。这些事实由两部分属性组成:维度属性(咱们称为键)和度量属性(咱们称为值)。由于不少维度属性是分层的,甚至有多层,好比日期维度中年/月/日或者周/季度/年。那么单一事实就须要根据这些层次维度汇聚成多个物化视图,来知足数据分析中的上卷和下钻操做。一个谨慎的数据仓库设计要求一个事实在多个聚合和物化中保持一致性。
2.1 数据模型
在Mesa中,数据以表的形式存储。每张表有它的模型(schema)来描述它的结构。一个表模型有它的键空间K和相应的值空间V,K和V在这里都是集合。表模型也有它的聚合函数F: V × V -> V 用来聚合跟同一键相关的多个值。聚合函数必须知足结合律。在不少状况下,它也知足交换律,尽管Mesa中包含不知足交换律的聚合函数。表模型中也包含一个或者多个K的全序索引。
键空间K和值空间V表现为列的二元组。他们都有固定的数据类型,表模型为每一个单独的列指定了聚合函数F,F隐式的定义成以下形式(译者注:说白了,就是把V放在一块儿写,对应于每一个二元组的聚合函数不单独写出来,统一写成个F): F((x1,.....,xk),(y1,.....yk)) = (f1(x1, y1),......fk(xk, yk))
其中(x1,.....,xk)和(y1,.....yk)都属于V,f1....fk这种形式是聚合函数的显式表现形式。(真蛋疼)
举个例子。图片1展现了Mesa中的三个表。这三张表都包含广告的点击量和费用,只不过被分散到不一样的属性中,好比按天的点击量,(译者注:图中的Date, PublisherId, Country, AdvertiserId都是key, Clicks和Cost是value)。做用于全部列的聚合函数是SUM。假设相同的底层事件更新了这三张表的数据,那么全部的指标都被一致的表如今三个表中。表1只是简单的呈现了表模型。在生产环境中,Mesa包含上千张表,每张表包含上百列,使用多个聚合函数。
2.2 更新和查询
为了实现大吞吐量的更新操做,Mesa采用批量更新。这些更新的批量包产生于Mesa系统外的上游系统,每隔几分钟产生(更小的频率更高的更新包可使更新操做延迟低,可是它须要消耗更多的资源)。每次更新,Mesa都会指定一个版本号 n (从0开始的序列)以及这些更新行的构成(表名,键,值)。每个(表名,键)至多包含一个汇聚值。 Mesa上的一个查询包含一个版本号 n 和 键空间上的谓语P。返回值包含一行符合条件P的键,这些键出如今一些更新中并带上了版本号0到n。而数据值按照表结构中定义的聚合函数进行聚合后,返回聚合值。Mesa实际上支持更复杂的查询功能,可是全部的均可以当作对这种基本查询的预处理和后加工。 举个例子,图片2中的展现了两次关于图片1中的表的更新操做。为了保证表的一致性,每一个更新操做包含对两个表A,B的一致性的行(译者注:说白了,就是要同时更新两个表中的某一行),Mesa会自动算出表C的更新操做,这是由于它能够直接源自表B的更新操做。理论上说,一个单次的更新操做同时包含AdvertiserId和PublisherId属性也能够被用做更新这三张表,可是这个代价比较大,特别是在表包含大量的属性的状况下。 注意表C与如下这个表B的物化视图的关系:SELECT SUM(Clicks), SUM(Cost) GROUP BY AdvertiserId, Country. 这个查询能够直接看成Mesa中的表,这是由于查询中的SUM函数就是对表B中全部度量值列的汇聚函数。Mesa约束在全部的度量列上使用相同的聚合函数,才能称做物化视图。 为了使更新原子性,Mesa采用了多版本的方法。Mesa按版本号的顺序执行更新操做。经过在执行下一条更新操做以前彻底合并这次更新操做来确保原子性。用户永远感觉不到局部合并更新带来的影响。 严格的按顺序更新带来的不只仅是原子性的应用。Mesa中的有些聚合函数不知足交换律,好比在标准的Key-Value存储中,一个(Key, Value)的更新彻底覆盖它以前的值。更细致的来看,按顺序的约束使得Mesa支持将错误的事实用相反的行为来表示。特别的,谷歌使用欺诈探测来决定广告的点击是否合法。欺诈性的点击能够用相反的事实来表示。好比在上图2中,就能够跟一个版本2的更新,这个更新包括负值的点击数和费用,去标记以前处理的点击数是非法的。经过严格的按顺序更新,Mesa保证了负的更新事实永远不会在它的正事实以前被合并。
2.3 数据版本管理
数据版本在Mesa的更新和查询中扮演了十分重要的角色。可是它也带来了不少挑战。首先,对于那些能够被聚合的广告统计数据,单独存储每个版本从存储的角度来看很是昂贵。聚合后的数据量就要小的多。其次,在查询的时候,遍历全部的版本而且聚合它们的代价也很大,而且会加大查询的延迟。再次,在每次更新时都提早聚合全部的版本也须要极高的代价。 为了处理这个问题。Mesa提早聚合某些版本的数据而且使用deltas存储(译者注:说白了就是分版本区间存储),每个delta包含一组不重复键的数据,以及一个delta版本号,用[V1, V2]表示,其中V1和V2是更新操做版本号,而且V1小于或等于V2。咱们用版本号来表示delta就很清楚了。delta[V1, V2]中的行指的是那些出如今版本号为V1和V2之间的更新操做的键,值对应的就是这些更新操做聚合后的值。更新操做被当作是一个单例delta合并进Mesa。一个单例delta版本[V1, V2]知足V1=V2=n, 其中n就是这次更新的版本号。 delta[V1, V2]和delta[V2+1, V3]能够经过简单的合并键/聚合值的方式合并成一个delta[V1, V3](2.4章节中会讨论,全部的行都是以键的方式存储的,因此说,两个delta能够在线性时间内合并完成),这个计算的正确性是由聚合函数F确保的。这个正确性并不依赖函数F的交换律。不管什么时候Mesa经过一个给定的键合并两个值时,delta的版本都是形如[V1, V2]和[V2+1, V3]的,而且这个操做是在不断增加的有序版本号上进行的。 Mesa仅仅容许用户查询一段时间之内的全部版本,好比24小时之内的。这就说明,早于这个时间的版本就能够聚合到一个基础delta中,设它的版本号为[0, B], 其中B大于或等于0,这样,任意一个delta[V1, V2]只要知足0 <= V1 <= V2 <= B就能够被删除。这个过程被称为base compaction(基础压缩聚合,译者注:真不知道该如何翻译这个专业名词)。Mesa同其余操做,好比查询和更新,并发的异步执行这个base compaction操做。 注意一下,跟更新版本有关的的时间是由那个版本生成的,它独立于数据中的任什么时候间信息。举个例子,图1中的Mesa表,数据中的2014/01/01这个时间是永远不会被移除的。Mesa可能会拒绝超过某个时间后的版本的查询。数据中的时间数据实际上是另一个属性而且它对Mesa不透明(译者注:提醒读者数据中的时间和Mesa中记录版本的时间不要混为一谈)。 有了base compaction, 回答某个版本n上的查询,咱们能够聚合一个基本的delta[0, B]和一系列单例delta[B+1, B+1]. [B+2, B+2],...,[n,n],而后返回值。虽然咱们常常的聚合成一个基础delta(好比说天天),可是咱们的单例delta个数很容易上百,甚至上千,特别是对于那些更新密集的表。为了支持更高效的查询,Mesa包含了一些形如[U,V]的累积delta D,其中B < U < V。这些累积的delta能够被用来求解一个版本n的delta划分,好比{[0, B],[B+1, V1],[V1+1, V2],...,[Vk+1, n]},这样就比直接使用单例delta须要更少的聚合操做。固然,这些累积delta也须要一些处理和存储上的开销。可是这些开销被分摊到了全部的操做中去了,特别是查询操做。因此用这些delta代替单例delta是可行的。 delta的聚合策略决定了每一个时刻deta在Mesa上是如何维护的。它的基本目的是平衡那些查询操做,更新操做以及处理和存储累积delta的开销。这个delta的策略要考虑三件事情:1. 哪些delta(除了单例delta)须要优先生成来知足这些更新版本能够被查询到。这个操做是在更新路径上同步进行的,会下降更新的速度。2. 哪些delta是能够在更新路径之外异步的生成的。3. 那些delta是能够被删除的。 如图3所示的一个delta汇聚策略就是一个双重级别的策略。在这种策略中,任什么时候刻都存在一个基本delta[0, B], 一系列的累积delta[B+1, B+10], [B+1, B+20],[B+1, B+30],...以及B之后的全部单例delta。每当第B+10X个版本合并时,就异步的生成delta[B+1, B+10X]。新的基础delta[0, B1]天天生成一次,可是这个新的基础delta在全部基于它的累积delta还没彻底生成以前是不可用的。当基础delta B切换到B1时,这个策略就将老的基础delta,累积delta以及全部B1版本以前的单例delta删除。这样的话,一个查询就只须要一个基础delta,一个累积delta和几个单例delta组合完成,大大减小了查询时的工做量。 Mesa目前所使用的是两级别delta的变种策略,它使用多种级别的累积delta,对于最近的版本,累积delta包含少许的单例delta,对于比较老的版本,累积delta包含较多的单例delta。一个delta层级可能包含一个基础delta,一个包含100个版本的delta,一个包含10个版本的累积delta,以及多个单例delta。相似的基于日志结构的存储引擎有LevelDB和BigTable。咱们注意到,基于差别更新的Mesa维护数据的方式,是一个简单的对不一样存储模型的适配。而且它能够被用于增加性视图和列存的更新。(译者注:我真看不懂这句话,随便翻译的。)
2.4 物理数据和索引形式
Mesa中的delta是基于delta聚合策略来建立和删除的。一旦delta被建立,它就是不可变的,因此物理的存储结构不须要支持高效的增量更新。 不可变的delta就容许Mesa使用一个至关简单的存储结构。由于存储是Mesa的主要开销,所以,对这种存储结构的基本要求就是省空间。Mesa还必须支持根据键的快速查找,由于一个查询每每关系几个delta,而后根据键将值聚合起来。为了使查询键变的高效,每一个Mesa表包含一个或多个表索引,每一个表索引都包含一个根据索引排序的数据的拷贝(译者注:空间换时间咯)。 存储结构的细节比较偏向技术,因此咱们只关注最重要的部分。delta中的行按顺序存储在有大小限制的数据文件中(这是针对文件系统文件大小限制的优化)。这些行自己被组织在行块中,每一个行块被单独的变换和压缩。每一个行块中的数据按列式存储来进行变换压缩,提升压缩率。由于存储是Mesa主要的开销,而且在查询时解压性能比写入时压缩性能重要。因此咱们在选用压缩算法的时候更强调压缩比和解压速率。 Mesa为每份数据文件存储一份索引文件。每一个索引实例包含一个行块的短键,这个短键由这个行块第一个键的固定长度前缀以及这个压缩行块在数据文件中的偏移量组成。那么查询一个指定的键的算法就能够分为两步,首先经过二分法从索引文件中找出可能包含这个短键的行块,而后在这个压缩的行块中经过二分法找到想要的键。
这一篇就翻译到这里,其中的思想很值得借鉴,有些开源的项目已经采用了部分技术。下一篇咱们一块儿看看Mesa的架构。
网易云免费体验馆,0成本体验20+款云产品!
更多网易研发、产品、运营经验分享请访问网易云社区。
文章来源: 网易云社区