1.基本概述
- Dremel是一款海量数据交互式分析工具
- Dremel和MapReduce并不是互相替代,而是相互补充的技术。在不同的应用场景下各有其用武之地。
- Drill的设计目标就是复制一个开源的Dremel,但是从目前来看,该项目无论是进展还是影响力都达不到Hadoop的高度。
2.产生背景
虽然 MapReduce 在处理数据时的确有其便捷性。但是当利用 MapReduce 从海量的数据集中提取出有效的特征时,很可能需要等待几个小时甚至更长时间才能出结果,假如发现代码的算法有问题,无法有效地提取特征,因此又重新修改了代码,并再次运行。这样的过程可能要反复好几 次,总的耗时可能多达数天,所以效率极低。
就此Google的团队结合其自身的实际需求,借鉴搜索引擎和并行数据库的一些技术,开发出了实时的交互式查询系统Dremel。
3.支持的应用
4.数据模型
-
技术支撑
Google的数据平台需要满足通用性,不同平台之间能够很好地实现数据的交互处理
- 统一的存储平台:实现高效的数据存储,Dremel使用的底层数据存储平台是GFS
- 统一的数据存储格式:存储的数据才可以被不同的平台所使用
-
面向记录和面向列的存储
Google的Dremel是第一个在嵌套数据模型基础上实现列存储的系统
- 处理时只需要使用涉及的列数据
- 列存储更利于数据的压缩
-
嵌套模型的形式化定义
字符τ是一个数据类型的定义,可以是原子类型,也可以是记录类型,Ai代表该τ的命名,即Ai就是某个τ类型的变量
-
原子类型
原子类型允许的取值类型包括整型、浮点型、字符串等
-
记录类型
记录类型则可以包含多个域,是使用递归方式定义的,即τ能够由其余以前定义好的τ组成,就像c中的结构体,与结构体不大相同的是,每一个包含的τ的值能够有多个(*,repeated,相似c中的数组),还能够是可选的(?,optional,以前那个数组能够不包含任何元素)
-
-
嵌套结构的模式和实例
5.嵌套式的列存储
关系型数据库中采用列存储有其便利之处,因为在不同列中相同位置的数据必然属于原数据库中的同一行,因此我们可以直接将每一列的值按顺序排列下来,不用引入其他的概念,也不会丢失数据信息。
嵌套式数据结构的列存储,数据本身之间的关系比关系数据库要复杂。存储后的数据本身反映不出任何结构上的信息,因此存储中除了记录值,还要记录结构。另外,所有的列存储在应用时往往要涉及多个列,如何按照正确的顺序快速地进行数据重组也是列存储需要解决的。
-
数据结构的无损表示
- Code(Name.Language.code)可重复深度的取值为0:没有重复、1:Name重复和2:Language重复
- 定义深度表示“值的路径中有多少可以不被定义”的字段实际是有定义的
- 重复深度主要关注的是可重复类型,而定义深度同时关注可重复类型和可选类型(optional)
- 每一列最终会被存储为块(Block)的集合,每个块包含重复深度和定义深度且包含字段值
-
高效的数据编码
- Dremel利用图中算法创建一个树状结构
- 核心的想法是只在字段writer有自己的数据时执行更新,非绝对必要时不尝试往下传递父节点状态。
- 树的节点为字段的writer,它的结构与模式中的字段层级匹配
- 子节点writer继承父节点的深度值
- 当任意值被添加时,子writer将深度值同步到父节点
-
数据重组
r1的完整数据重组过程
如果具体的查询中不是涉及所有列,而是仅涉及很少的列的话,上述数据重组的过程会更加便利,下图中仅仅涉及DocId和Name.Language.Country的有限状态机
有限状态机的构造算法,核心思想是设置t为当前字段读取器的当前值f所返回的下一个重复深度。在模式树中,找到它在深度 t 的祖先,然后选择该祖先节点的第一个叶子字段 n。由此得到一个FSM状态变化(f,t)->n
6.查询语言与执行
- Dremel中的数据都是分布式存储的,因此每一层查询涉及的数据实际都被水平划分后存储在多个服务器上
- Dremel是一个多用户系统,因此同一时刻往往会有多个用户进行查询
- 查询分发器有一个很重要参数,它表示在返回结果之前一定要扫描百分之多少的tablet
Dremel的SQL查询输入的是一个或多个嵌套结构的表以及相应的模式,而输出的结果是一个嵌套结构的表以及相应的模式
Dremel利用多层级服务树(multi-level service tree)的概念来执行查询操作
根服务器
:接受客户端发出的请求,读取相应的元数据,将请求转发至中间服务器。中间服务器
:负责查询中间结果的聚集叶子服务器
:负责执行数据来源
7.性能分析
-
Google的实验数据集规模
-
MR从面向记录转换到列状存储后性能提升了一个数量级(从小时到分钟),而使用Dremel则又提升了一个数量级