Google Dremel Principle - How to Analyze 1PB in 3 Seconds

With the popularity of Hadoop , large-scale data analysis systems have become more and more popular. Data analysts need an interactive system that "plays" with data. In this way, it is very convenient and quick to browse the data and establish an analysis model. The Dremel system has the following main features:

  • Dremel is a large scale system. On a petabyte-level dataset, reducing the task to the second level undoubtedly requires a lot of concurrency. The sequential read speed of the disk is around 100MB/S, so processing 1TB of data in 1S means that at least 10,000 disks need to be read concurrently! Google has always been a good player in doing big things with cheap machines. However, the more machines there are, the greater the probability of problems. With such a large cluster size, sufficient fault tolerance needs to be considered to ensure that the speed of the entire analysis is not affected by individual slow (bad) nodes in the cluster.
  • Dremel is a complement to the lack of MR interactive query capabilities. Like MapReduce, Dremel also needs to run with the data, moving computations onto the data. So it needs a file system like GFS as a storage layer. At the beginning of design, Dremel is not a replacement for MapReduce. It can only perform very fast analysis. When used, it is often used to process MapReduce result sets or to build analysis prototypes.
  • Dremel's data model is nested. Internet data is often non-relational. Dremel also needed to have a flexible data model, which was crucial. Dremel supports a nested data model, similar to Json. The traditional relational model, due to the inevitable large number of Join operations, is often powerless when dealing with such large-scale data.
  • Data in Dremel is stored in columnar format. Using columnar storage, when analyzing, you can only scan the required part of the data, reducing the amount of CPU and disk access. At the same time, columnar storage is compression-friendly. Using compression, you can combine CPU and disk to maximize performance. For relational data, we all have experience with columnar storage. But for nested structures, Dremel can also use column storage, which is very worth learning.
  • Dremel combines the technologies of web search and parallel DBMS. First, he draws on the concept of "query tree" in Web search, which divides a relatively huge and complex query into smaller and simpler queries. The big things are reduced to the small ones, and the small things can be run concurrently on a large number of nodes. Second, similar to parallel DBMSs, Dremel can provide a SQL-like interface, just like Hive and Pig do.

Google Dremel application scenarios

Imagine a usage scenario. Our beauty data analyst, she has a new idea to test. To verify her idea, she needs to run a query on hundreds of millions of pieces of data to see if the result is the same as her idea. She doesn't want to wait too long, and it is best to have the result in a few seconds. Of course, her ideas are not necessarily perfect, and she still needs to constantly adjust her sentences. Then she tested the idea and found value in the data. Finally, she can refine the statement into a long-running task.

For Google, data is initially placed on GFS. Data can be imported into Dremel through MapReduce, and some processing can be done in these MapReduce. Analysts then use Dremel to easily and happily analyze the data and build models. Finally, it can be programmed into a long-running MapReduce task.

This processing method reminds me of Greenplum's Chorus. Chorus can also provide fast data queries for analysts, but the solution is to import some data through preprocessing to reduce the size of the data set. Thirty-six strategies are used, which is the best strategy to avoid the problem of instantaneous analysis of big data . Chorus is about to open source recently, you can pay attention.

Also special is the nested data format stored in columns. As shown, in the store-by-record mode, multiple columns of a record are written together consecutively. In column-wise storage, data can be separated by columns. That is, it is possible to just scan ABC without reading AE or ABC. The difficulty is how we can efficiently scan several columns at the same time and do some analysis.



 

Google Dremel data model

At Google, Protocol Buffer is often used as a serialization solution. Its data model can be strictly expressed mathematically as follows:

t=dom|<A1:t[?|?],...,An:t[?|?]>

其中t可以是一个基本类型或者组合类型。其中基本类型可以是integer,float和string。组合类型可以是若干个基本类型拼凑。星号 (*)指的是任何类型都可以重复,就是数组一样。问号(?)指的是任意类型都是可以是可选的。简单来说,除了没有Map外,和一个Json几乎没有区别。

下图是例子,Schema定义了一个组合类型Document.有一个必选列DocId,可选列Links,还有一个数组列Name。可以用Name.Language.Code来表示Code列。



 

这种数据格式是语言无关,平台无关的。可以使用Java来写MR程序来生成这个格式,然后用C++来读取。在这种列式存储中,能够快速通用处理也是非常的重要的。

上图,是一个示例数据的抽象的模型;下图是这份数据在Dremel实际的存储的格式。



 

如果是关系型数据,而不是嵌套的结构。存储的时候,我们可以将每一列的值直接排列下来,不用引入其他的概念,也不会丢失数据。对于嵌套的结构,我们 还需要两个变量R (Repetition Level) ,D (Definition Level) 才能存储其完整的信息。

Repetition Level是记录该列的值是在哪一个级别上重复的。举个例子说明:对于Name.Language.Code 我们一共有三条非Null的记录。

1.第一个是”en-us”,出现在第一个Name的第一个Lanuage的第一个Code里面。在此之前,这三个元素是没有重复过的,都是第一个。所以其R为0。

2.第二个是”en”,出现在下一个Lanuage里面。也就是说Lanague是重复的元素。Name.Language.Code中Lanague排第二个,所以其R为2.

3.第三个是”en-gb”,出现在下一个Name中,Name是重复元素,排第一个,所以其R为1。

我们可以想象,将所有的没有值的列,设值为NULL。如果是数组列,我们也想象有一个NULL值。有了Repetition Level,我们就可以很好的用列表示嵌套的结构了。但是还有一点不足。就是还需要表示一个数组是不是我们想象出来的。

Definition Level 是定义的深度,用来记录该列是否是”想象”出来的。所以对于非NULL的记录,是没有意义的,其值必然为相同。同样举个例子。例如Name.Language.Country,

  • 第一个”us”是在R1里面,其中Name,Language,Country是有定义的。所以D为3。
  • 第二个”NULL”也是在R1的里面,其中Name,Language是有定义的,其他是想象的。所以D为2。
  • 第三个”NULL”还是在R1的里面,其中Name是有定义的,其他是想象的。所以D为1。
  • 第四个”gb”是在R1里面,其中Name,Language,Country是有定义的。所以D为3。



 



 

就是这样,如果路径中有required,可以将其减去,因为required必然会define,记录其数量没有意义。

理解了如何存储这种嵌套结构。写没有难度。读的时候,我们只读其中部分字段,来构建部分的数据模型。例如,只读取DocID和 Name.Language.Country。我们可以同时扫描两个字段,先扫描DocID。记录下第一个,然后发现下一个DocID的R是0;于是该读 Name.Language.Country,如果下一个R是1或者2就继续读,如果是0就开始读下一个DocID。



 

下图展示了一个更为复杂的读取的状态机示例。在读取过程中使用了Definition Level来快速Jump,提升性能。



 

到此为止,我们已经知道了Dremel的数据结构。就像其他数据分析系统一样,数据结构确定下来,功能就决定了一大半。对于Dremel的数据查询,必然是“全表扫描”,但由于其巧妙的列存储设计,良好的数据模型设计可以回避掉大部分Join需求和扫描最少的列。

Google Dremel查询方式

Dremel可以使用一种SQL-like的语法查询嵌套数据。由于Dremel的数据是只读的,并且会密集的发起多次类似的请求。所以可以保留上次请求的信息,还优化下次请求的explain过程。那又是如何explain的呢?



 

这是一个树状架构。当Client发其一个请求,根节点受到请求,根据metadata,将其分解到枝叶,直到到位于数据上面的叶子Server。他们扫描处理数据,又不断汇总到根节点。

举个例子:对于请求:

SELECT A, COUNT(B) FROM T GROUP BY A

根节点收到请求,会根据数据的分区请求,将请求变成可以拆分的样子。原来的请求会变为。

SELECT A, SUM(c) FROM (R1 UNION ALL ... Rn) GROUP BY A

R1,…RN是T的分区计算出的结果集。越大的表有越多的分区,越多的分区可以越好的支持并发。

然后再将请求切分,发送到每个分区的叶子Server上面去,对于每个Server

Ri = SELECT A, COUNT(B) AS c FROM Ti GROUP BY A

结构集一定会比原始数据小很多,处理起来也更快。根服务器可以很快的将数据汇总。具体的聚合方式,可以使用现有的并行数据库技术。

Dremel是一个多用户的系统。切割分配任务的时候,还需要考虑用户优先级和负载均衡。对于大型系统,还需要考虑容错,如果一个叶子Server出现故障或变慢,不能让整个查询也受到明显影响。

通常情况下,每个计算节点,执行多个任务。例如,技巧中有3000个叶子Server,每个Server使用8个线程,有可以有24000个计算单 元。如果一张表可以划分为100000个区,就意味着大约每个计算单元需要计算5个区。这执行的过程中,如果某一个计算单元太忙,就会另外启一个来计算。 这个过程是动态分配的。

对于GFS这样的存储,一份数据一般有3份拷贝,计算单元很容易就能分配到数据所在的节点上,典型的情况可以到达95%的命中率。

Dremel还有一个配置,就是在执行查询的时候,可以指定扫描部分分区,比如可以扫描30%的分区,在使用的时候,相当于随机抽样,加快查询。

Google Dremel测试实验

实验的数据源如下表示。大部分数据复制了3次,也有一个两次。每个表会有若干分区,每个分区的大小在100K到800K之间。如果压缩率是25%, 并且计入复制3份的事实的话。T1的大小已经达到PB级别。这幺小且巨量的分区,对于GFS的要求很高,现在的Hdfs稳定版恐怕受不了。接下来的测试会 逐步揭示其是如何超过MR,并对性能作出分析。

列存测试

首先,我们测试看看列存的效果。对于T1表,1GB的数据大约有300K行,使用列存的话压缩后大约在375MB。这台机器磁盘的吞吐在70MB/s左右。这1GB的数据,就是我们的现在的测试数据源,测试环境是单机。

见上图。

  • 曲线A,是用列存读取数据并解压的耗时。
  • 曲线B是一条一条记录挨个读的时间。
  • 曲线C是在B的基础上,加上了反序列化的时间。
  • 曲线d,是按行存读并解压的耗时。
  • 曲线e加上了反序列化的时间。因为列很多,反序列化耗时超过了读并解压的50%。

从图上可以看出。如果需要读的列很少的话,列存的优势就会特别的明显。对于列的增加,产生的耗时也几乎是线性的。而一条一条该个读和反序列化的开销是很大的,几乎都在原来基础上增加了一倍。而按行读,列数的增加没有影响,因为一次性读了全部列。

Dremel和MapReduce的对比测试

MR和Dremel最大的区别在于行存和列存。如果不能击败MapReduce,Remel就没有意义了。使用最常见的WordCount测试,计算这个数据中Word的个数。

Q1: SELECT SUM(CountWords(txtField)) / COUNT(*) FROM T1

上图是测试的结果。使用了两个MR任务。这两个任务和Dremel一样都运行在3000个节点上面。如果使用列存,Dremel的按列读的MR只需 要读0.5TB的数据,而按行存需要读87TB。 MR提供了一个方便有效的途经来讲按行数据转换成按列的数据。Dremel可以方便的导入MapReduce的处理结果。

树状计算Server测试

接下来我们要对比在T2表示使用两个不同的Group BY查询。T2表有24 billion 行的记录。每个记录有一个 item列表,每一item有一个amount 字段。总共有40 billion个item.amount。这两个Query分别是。

Q2: SELECT country, SUM(item.amount) FROM T2 GROUP BY country

Q3: SELECT domain, SUM(item.amount) FROM T2 WHERE domain CONTAINS ’.net’ GROUP BY domain

Q2需要扫描60GB的压缩数据,Q3需要扫描180GB,同时还要过滤一个条件。

上图是这两个Query在不同的server拓扑下的性能。每个测试都是有2900个叶子Server。在2级拓扑中,根server直接和叶子 Server通信。在3级拓扑中,各个级别的比例是1:100:2900,增加了100个中间Server。在4级拓扑中,比例为 1:10:100:2900.

Q2可以在3级拓扑下3秒内执行完毕,但是为他提供更高的拓扑级别,对性能提升没有裨益。相比之下,为Q3提供更高的拓扑级别,性能可以有效提升。这个测试体现了树状拓扑对性能提升的作用。

每个分区的执行情况

对于刚刚的两个查询,具体的每个分区的执行情况是这样的。

可以看到99%的分区都在1s内完成了。Dremel会自动调度,使用新的Server计算拖后腿的任务。

记录内聚合

由于Demel支持List的数据类型,有的时候,我们需要计算每个记录里面的各个List的聚合。如

Q4 : SELECT COUNT(c1 > c2) FROM

(SELECT SUM(a.b.c.d) WITHIN RECORD AS c1,

SUM(a.b.p.q.r) WITHIN RECORD AS c2

FROM T3)

我们需要count所有sum(a.b.c.d)比sum(a.b.p.q.r),执行这条语句实际只需要扫描13GB的数据,耗时15s,而整张表有70TB。如果没有这样的嵌套数据结构,这样的查询会很复杂。

扩展性测试

Dremel有良好的扩展性,可以通过增加机器来缩短查询的时间。并且可以处理数以万亿计的记录。

对于查询:

Q5: SELECT TOP(aid, 20), COUNT(*) FROM T4 WHERE bid = fvalue1g AND cid = fvalue2g

使用不同的叶子Server数目来进行测试。

可以发现CPU的耗时总数是基本不变的,在30万秒左右。但是随着节点数的增加,执行时间也会相应缩短。几乎呈线性递减。如果我们使用通过CPU时间计费的“云计算”机器,每个租户的查询都可以很快,成本也会非常低廉。

容错测试

一个大团队里面,总有几个拖油瓶。对于有万亿条记录的T5,我们执行下面的语句。

Q6: SELECT COUNT(DISTINCT a) FROM T5

值得注意的是T5的数据只有两份拷贝,所以有更高的概率出现坏节点和拖油瓶。这个查询需要扫描大约1TB的压缩数据,使用2500个节点。

可以看到99%的分区都在5S内完成的。不幸的是,有一些分区需要较长的时间来处理。尽管通过动态调度可以加快一些,但在如此大规模的计算上面,很难完全不出问题。如果不在意太精确的结果,完全可以小小减少覆盖的比例,大大提升相应速度。

Google Dremel 的影响

Google Dremel的能在如此短的时间内处理这么大的数据,的确是十分惊艳的。有个伯克利分校的教授Armando Fox说过一句话“如果你曾事先告诉我Dremel声称其将可做些什么,那么我不会相信你能开发出这种工具”。这么给力的技术,必然对业界造成巨大的影 响。第一个被波及到的必然是Hadoop。

Dremel与Hadoop

Dremel的公开论文里面已经说的很明白,Dremel不是用来替代MapReduce,而是和其更好的结合。Hadoop的Hive,Pig无 法提供及时的查询,而Dremel的快速查询技术可以给Hadoop提供有力的补充。同时Dremel可以用来分析MapReduce的结果集,只需要将 MapReduce的OutputFormat修改为Dremel的格式,就可以几乎不引入额外开销,将数据导入Dremel。使用Dremel来开发数 据分析模型,MapReduce来执行数据分析模型。

Hadoop的Hive,Pig现在也有了列存的模式,架构上和Dremel也接近。但是无论存储结构还是计算方式都没有Dremel精致。对 Hadoop实时性的改进也一直是个热点话题。要想在Hadoop中山寨一个Dremel,并且相对现有解决方案有突破,笔者觉得Hadoop自身需要一 些改进。一个是HDFS需要对并发细碎的数据读性能有大的改进,HDFS需要更加的低延迟。再者是Hadoop需要不仅仅支持MapReduce这一种计 算框架。其他部分,Hadoop都有对应的开源组件,万事俱备只欠东风。

Dremel的开源实现

Dremel现在还没有一个可以运行的开源实现,不过我们看到很多努力。一个是Apache的Drill,一个是OpenDremel/Dazo。

OpenDremel/Dazo

OpenDremel是一个开源项目,最近改名为Dazo。可以在GoogleCode上找到http://code.google.com/p/dremel/。目前还没有发布。作者声称他已经完成了一个通用执行引擎和OpenStack Swift的集成。笔者感觉其越走越歪,离Dremel越来越远了。

Apache Drill

Drill 是 Hadoop的赞助商之一MapR发起的。Drill作为一个Dremel的山寨项目,有和Dremel相似的架构和能力。他们希望Drill最终会想 Hive,Pig一样成为Hadoop上的重要组成部分。为Hadoop提供快速查询的能力。和Dremel有一点不同,在数据模型上,开源的项目需要支 持更标准的数据结构。比如CSV和JSON。同时Drill还有更大的灵活性,支持多重查询语言,多种接口。

现在Drill的目标是完成初始的需求,架构。完成一个初始的实现。这个实现包括一个执行引擎和DrQL。DrQL是一个基于列的格式,类似于Dremel。目前,Drill已经完成的需求和架构设计。总共分为了四个组件

  • Query language: A query language similar to Google BigQuery that supports nested models, named DrQL.
  • Low-lantency distribute execution engine: An execution engine that can support massive scaling and fault tolerance. Can run on tens of thousands of machines to calculate petabytes of data.
  • Nested data format: Nested data model, similar to Dremel. CSV, JSON, YAML and similar models are also supported. This allows the execution engine to support more data types.
  • Scalable data source: Supports multiple data sources. At this stage, Hadoop is used as the data source.

At present, these four components are being actively promoted respectively, and Drill also very much hopes that other companies in the community will join. Drill wants to join the Hadoop ecosystem.

last words

This article introduces Google Dremel usage scenarios, design implementation, testing experiments, and impact on the open source world. I believe that in the near future, Dremel's technology will be widely used.

 

Reprinted from: http://blog.csdn.net/happyduoduo1/article/details/51784730

http://blog.csdn.net/dc_726/article/details/41627613

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=327038206&siteId=291194637