Mesa - 谷歌近实时分析型数据仓库
Paper阅读系列,主要是一些Paper阅读后,整理的阅读笔记和个人对一些关键思想的理解,方便自己健忘的时候翻出来快速复习一下 ;)
这个第一帖,选取Mesa这个几乎没有什么热度的系统,炒冷饭示例帖,原文发在CSDN博客,略有修订
目标问题
谷歌Mesa是一个服务于谷歌广告业务的近实时分析型数据仓库, 其设计目标包括:
- 原子更新操作 :跨指标,跨视图原子更新
- 一致性:跨数据中心强一致性
- 高可用性:无单点
- 近实时海量数据更新: 每秒百万行的写入吞吐率,分钟级别内跨数据中心可见
- 海量查询下的低延迟: 单点查询,99%的概率在百毫秒级别内
- 水平拓展: 支持PB级别以上数据
- 在线数据/元数据变更(不影响线上读写业务)
好吧,光看这些要求,想象一下就很 🐂 的样子
基本业务模型
Mesa不是一个完全从头构建的系统,而是构建在谷歌已有的几个分布式系统服务至上,它使用Bigtable存储元数据,GFS/Colossus存储Data,MapReduce进行批量计算
对用户而言,其基本数据模型就是一个类KV型数据仓库,Mesa表里面的每一行数据,由一组 维度(key)/和度量值(value)来定义,基本对应的一张事实表的概念,如下图例:
基于Mesa服务的广告系统的Metrics数据普遍的可聚合性,Mesa要求对值空间的的每个字段定义一个聚合函数,聚合函数要求满足结合律,最好具备交换律。
数据本身的存储,采用MVCC的模式进行版本标识,在数据更新和查询时,需要指定版本。
Mesa最基本的查询操作是指定查询版本N,以及Key的过滤条件,其返回结果是满足查询条件的Key在历史上0-N之间所有版本的数据,这些数据按照表结构中定义的聚合函数进行聚合后,返回聚合值。
为了提高数据入库性能,在更新数据时,Mesa上层业务系统通过批量提交更新数据来达到所需要的吞吐率。
底层实现
在海量数据规模下,实时性和吞吐率两个指标,从来都是一对矛盾,Mesa基于广告数据可聚合性的特质,从存储,查询等角度进行了大量针对性的设计
增量聚合
基于广告系统Metrics数据普遍的海量数据聚合查询应用场景,Mesa对历史版本数据会进行预聚合操作,并删除聚合之前的独立数据,一方面减少查询时需要的聚合计算量,另一方面减少所需要的数据存储量。
预聚合操作意味着对数据需要进行大量的计算和重写的工作,对于大量频繁更新的数据集,在效率和代价之间是需要进行平衡的,Mesa的解决方案是提供基础聚合0-n的全量历史数据和增量聚合(Delta)类似(n1-n2),(n2-n3),(n3-n4)增量数据这样的两层聚合策略。
增量聚合会带来众多的Delta文件,而聚合查询又是Mesa系统的基本应用场景,性能至关重要,这就要求Mesa能够快速的在众多Delta文件中快速检索到相关键值。
索引
Mesa的解决方案和其它类似系统相似,数据按对应的索引序排序分割成限定大小的文件,每个文件内部再按行分割成行组row blocks进行压缩存储,每个行组内部的数据在实际存储时,按列式存储的layout进行转换压缩,提高压缩率。
而索引文件由行键取固定长度的前缀组成,映射到对应数据行在行组内部的存储偏移量。因为是一个前缀,所以索引可能不能精确定位一行的位置,而是定位这一行在行组内的偏移范围,在通过二分查找的方式在行组内部定位到具体的行。
此外Mesa表也支持建立多个索引,便于从不同的维度进行数据检索,海量数据中的多索引的支持,从性能的角度来说一直都是一个巨大的挑战,Mesa采取的方式是为每个索引维护一份自己独立的数据拷贝,大体就是用空间换时间了。
数据版本
Mesa中Version版本的概念和BigTable/HBase相比较,形式类似,但是整体目的用途,感觉有些差异
HBase系统中的版本,尽管从理论上可以认为是行/列以外的又一个存储维度,但实际系统的设计导向,基本就是作为区分数据的历史版本使用,有不少其它系统(比如Percolator/Trafodion)借助于HBase的Cell版本功能,构建起MVCC的机制来实现例如跨行跨表原子操作,OLTP等特性。
但是在Mesa中,除了构建原子操作,从查询方式(返回所有0-n版本聚合后的数据)和预聚合合并Delta文件等系统整体设计思路的角度来看,其版本的功能指向,更接近时间序列的概念,用来罗列相同Key下的可聚合的细粒度数据,当然,实际应用可能性取决于聚合函数的定义(比如假设有一个聚合函数是LastVersion,那就接近HBase的版本概念了)
Compaction
除了索引,对增量聚合Delta文件进行合并也是提升性能的常见方案,整体流程上,批量更新数据,及时刷新增量文件到磁盘,定时合并增量文件,将增量文件规整为Base基础数据文件,这些都是业内标准的做法。
Mesa中的这些概念和HBase的Memory Store -> flush-> Minor compaction ->Major compaction的整体流程概念也很相似。
但是与HBase/Bigtable的区别在于,批量的写操作,Mesa是直接通过外部系统提交批量数据来实现,HBase则是借助于Memory Store/Flush机制来缓冲,将随机写累积成批量写
Mesa因此需要外部系统配合,不过,也减少了服务自身的复杂性。
底层文件合并,目的都是为了提升检索效率,但是HBase更多的是做简单(或者说通用)的数据归并动作,将无效数据(比如Delte掉的数据,超过历史版本数量的数据)剔除,减少文件数量等,本质上不改变数据的形态,性能的收益是从检索本身的开销上获得的
而对于Mesa来说,其工作的重点是历史数据的聚合(剔除一行的动作是通过负值Value来实现),本质上是将细粒度数据转化为粗粒度数据的过程(当然,和前面说的,实际上,取决于聚合函数的定义,可能可以达到其它目的),性能的改善更多的是从数据的形态变化上获得的。
Mesa实例
为了保证服务的不间断,一个Mesa实例被拆分成两个独立不相关的子系统。一个负责更新数据和进行日常维护(比如预聚合,增量文件合并,元数据变更等),一个负责数据查询工作
更新维护子系统由controller(多个)和worker(多个)组成,controller自身是无状态的,同时可以按照表为单位进行拆分,负责管理元数据和具体任务的调度,自身不直接进行数据维护工作,worker按工作类型分组组成一个worker池,空闲的worker主动向controller拉取相关任务。
从可用性的角度来说,一方面,该子系统的维护更新不影响数据查询子系统的工作,另一方面controller和worker的上述特性使得各个组件的维护工作对该子系统自身造成的影响的最小化。
查询子系统由多个Query server组成,这些Server在一个Mesa实例内部再分成几组(Sets),每一组都能完全服务一个mesa实例内部的所有表,客户端通过全局的Locator定位服务定位使用哪一个Query Server,这样多个Sets可以在线进行滚动维护,不影响查询服务的提供。
一个Set内部的任何一个Query Server理论上也能覆盖所有的table,但是为了提高查询性能,利用查询Cache,每个Server会在locatator Service中注册它所定向服务的表,便于客户端路由到对应的Server。
这种维护节点和查询节点分离的思想,在很多系统上都可以看到类似的身影,比如Druid。整体上来说,就是将不同类型的任务明确拆分为不同的角色,降低单个组件的复杂度和系统维护难度,提升系统吞吐能力。
多个Mesa实例部署在多个数据中心,构成一个整体的容灾或负载均衡系统,Mesa实例自身不处理跨实例的协调工作,由外部上层应用来协调处理,决策内容提交给各个实例的Controllers执行
数据同步方面,通过基于Paxos的协议处理跨数据中心同步问题(主要是元数据信息),元数据以同步方式进行跨数据中心复制,数据本身通过独立的异步方式进行复制
其它优化,工程实现等
Scan to seek : 如果查询条件的过滤字段不是索引组合键的第一个字段,对过滤字段的左侧字段进行枚举检索,尽量减少需要进行范围检索的工作
Resume key:海量数据的返回是分批返回的,返回结果中附带一个Resume key用作标识当前进度,便于后续查询可以在此基础上继续进行(比如当前服务的Query Server崩溃了,可以换一个Query Server继续服务)
Mesa系统内部的日常数据维护工作可能涉及到大量读写工作,采用了MR作业来分布式的进行,而要保证MR作业的时间可控性,正确的进行分区,避免数据倾斜会是一个需要妥善解决的问题,Mesa采用数据采样的方式,对每个Delta文件同步存储一个采样文件,通过预读采样文件,决定MR任务分区的键值
对于表结构Schema的在线变更,Mesa提供两种方式,一是使用新的schema全量拷贝数据到新的版本上,二是在特定的表结构变更场景中(比如增加字段的这种表结构变更操作),在查询的时候动态判断schema版本,对返回数据进行转换,(增加字段的变更为例,Mesa会为老数据补上默认值),这个过程只需要维持一段特定的时间,因为MESA内的数据经过一段时间会进行Delta增量合并操作,在合并过程中Mesa再对涉及到的历史数据进行格式转换操作。
此外,在大规模集群下,通常一些小概率事件也可能出现,比如内存翻转等偶发硬件错误,照成数据错误,Mesa还加强了一些数据校验的环节步骤。
小结
整体看来,Mesa并不是一个从底层开始重新构建的系统,它依托Colossus提供分布式数据存储服务,依托Bigtable做元数据存储。使用MapReduce进行批量数据处理工作。
之所以能实现它所声称的这些底层系统所不具备的综合能力(高一致性+原子更新+低延时+近实时+海量吞吐率),其原因还是因为它针对了广告数据的应用场景,采用了各类最佳实践和一些特定的Tradeoff策略,比如:
- 通过批量的数据操作提高吞吐率 (意味着,限制了更新的最小latency,分钟级延迟)
- 通过MVCC机制解决原子更新,读写一致性等问题
- 数据采用行分割做水平扩展,列存储格式提升存储密度和查询性能
- 通过空间换时间提升二级索引的性能(每个索引需要一份独立的数据拷贝)
- 采用Delta增量数据预聚合的方式减少查询计算量,数据存储量等(仅适用于Mesa服务的广告metrics系统,数据天然的聚合特性这种场合)
- 基本低效策略和特定场景高效定制策略相结合针对性解决高难度问题(比如上述元数据结构在线变更的两个解决方案,比如元数据和实际数据跨数据中心的两种同步方式)
- 各种服务的分层,分组隔离,无状态化,提升整体可用性
- 定制的优化策略,比如Scan to seek提升过滤检索效率,Resume key分批处理数据,增强容错性,数据采样辅助MR决策等
总体来说,个人感觉,Mesa相对于bigtable,megastore,spanner等通用系统,更像一个特定领域的解决方案,不过这个特定领域方案涵盖了很多普适的问题的解决思路,集成了大量的特定问题的最佳实践,在很多其它系统上都可以看到各种类似实现的身影,也可以做为我们自己开发系统时的思路借鉴。
Paper 链接
Mesa: Geo-Replicated, Near Real-Time, Scalable Data
Warehousing : https://research.google.com/pubs/archive/42851.pdf
常按扫描下面的二维码,关注“大数据务虚杂谈”,务虚,我是认真的 ;)