
我们可以通过存储插件连接到本地文件系统,Hive,HBase,或是其他的数据源。在Drill的web界面的存储插件配置tab,你可以查看修改这些插件的配置。如果不支持HTTPS(默认就没有),你可以访问HTTP://{IP}:8047/storage 来查看和配置存储插件。可以用IP,也可以用hostname。如果开启了https的支持,你可以通过https://{IP}:8047/storage来访问。 Drill 默认开启了cp,dfs,hbase,hive和mongodb的插件支持。 cp 指向Drill Classpath里的jar包文件,例如你可以查询employee.json文件。 DFS 指向本地文件系统,你也可以修改这个插件指向任何分布式文件系统,比如hadoop或是amazon的S3文件系统。 hbase 提供到HBase的连接 。 Hive 为Drill提供了访问Hive文件的元数据抽象的集成,也提供了一些库来访问SerDe和UDF. mongo 提供到mongodb的访问。 在Drill沙箱里,dfs插件为你提供了连接到一个预先定义好的hadoop环境的能力。如果你自己在本地跑一下drill,那么dfs是访问你本地文件系统的根目录。 注册一个存储插件的配置 你只需要输入插件名字,点击"CREATE",提供一个json格式的配置,再点击"UPDATE",就可以注册一个新的插件配置。。 存储插件的配置的持久化 在嵌入式执行的时候,Drill将配置保存在一个临时目录, 在分布式模式下运行时,drill将配置放在zookeeper中。例如,在Mac OSX下,Drill将配置保存在/tmp/drill/sys.storage_plugins文件中。当你重启电脑的时候,这个临时目录会被清空。当你将drill运行在嵌入模式下时,你可以将sys.store.provider.local.path 配置项添加到drill-override.conf文件里,就像下面这样: drill.exec: { cluster-id: "drillbits1", zk.connect: "localhost:2181", sys.store.provider.local.path="/mypath" }
存储插件是Drill中,连接到数据源的模块。一个存储插件通常会优化Drill查询的执行,提供数据的定位,命名空间下的配置和读数据要用到的格式。Drill已经内置了一些存储插件,你只需要根据你的环境配置一下就可以使用了。借助存储插件,你可以连接到各种数据源,像数据库,本地或是分布式的文件,或是Hive数据库。 你可以修改一个存储插件的默认配置X,并给一个新的唯一的名字"Y"。这个新的文档就会把Y当成一个完全不同的插件,虽然它本身只是原有插件重新配置了一下。当你执行一个drill查询的时候,Drill通过以下几种方式得到存储插件的配置: Query中的FROM语句指定要使用的插件。 在执行Query之前执行USE命令; 你还可以启动Drill的时候指令存储插件。 存储插件的内部 下图描述了位于Drill和数据源中间的存储插件层: 除了前面进到的这些功能,存储插件层还提供了扫描,写数据的功能,并能够将来自navive层的一些能力,比如动作推断,jon,SQL 等等知会到执行引擎。
(翻译自apache drill 官网。) Drill是从地基开始就奔向高性能和大数据集去设计的,下面列出来的是Drill能够做到高性能的核心要点。 分布式的引擎 Drill提供了一个强大的分布式引擎来处理查询。用户可以从集群的任何一个节点是提交查询。你可以添加新的节点到集群中,以为了支持更多用户的更多数据,或是获得更好的性能。 列式执行 通过使用一种纯内存的分层的,列式的数据模型,Drill同时为列式存储,列式执行都做了优化。当数据是存储在列式存储的文件上时(比如像Parquet)Drill会避免去访问那些查询中根本不涉及到的列。Drill的执行层同样可以直接对列式数据进行SQL查询,而不需要做一个分行化的操作。列式存储和直接列式执行,这两个优化的组件显示地降低了内存消耗,并为BI和分析类型的作业提供了更快的执行效率。 向量化 相比一次只处理一个表记录中的一个值 ,Drill中的向量化允许CPU在向量上操作,也就是一批记录上操作。一个记录批次包含来自不同的记录上的一组数值 。向量处理能够做到非常高效的技术基础,在于现在的芯片技术,这些芯片都携带了深度流水线化的CPU设计。让所有管理都达到接近峰值的高效是不可能的,因为代码复杂度太高了。 运行时编译 运行时编译相比解释执行提供了更快的执行。Drill为每一条查询指令都生成了非常高效的指令。下图展示了Drill的编译和指令生成过程。 乐观并且流水线的查询执行 Drill 使用乐观的执行模型来处理查询,假定在小片的查询中失败是不太常见的。Drill不会浪费时间在创建边界或是检查点上,这样就可以最小化恢复时间。在单条查询失败的时候,这条查询就直接返回了。Drill执行使用一种所有任务一次性安排的流水线模型。查询尽可能地在内存中执行以便能在流水线中完成作业,只有内存不足时才会持久化到磁盘。
(翻译自Drill官网) 核心模块 下图描述了一个drillbit里的各个组件 下面列出drillbit里的关键组件: RPC endpoint Drill开发了一种基于Probobuf的损耗非常低的RPC通信协议来跟客户端打交道。另外,客户端程序也可以使用C++或是JAVA api层来跟Drill交互。客户端可以直接指定跟哪些Drillbit节点打交道,也可以在提交查询前通过zookeeper服务来获取一定数量的drillbit节点信息。 我们推荐客户端总是通过zookeeper,以隔离集群管理的复杂性,不用关心像添加或是删除节点等等。 SQL解析器 Drill 使用calcite 这个开源的SQL解析框架来解析接收到的SQL查询。这个解析组件的输出是一个人类语言无法描述,但是机器易于理解的逻辑计划,这个逻辑计划能够刚好描述这个sql查询。 Storage plugin interface: Drill为好几种不同的数据源充当上面的查询层的角色。Drill里的存储层插件就描述了Drill怎样和这些数据源交互的抽象。存储插件给Drill提供以下信息: 在数据源里能得到的元数据; Drill读写数据源的接口; 数据的位置 ,以及一系列优化规则,这些优化规则能够让在特定的数据源上的drill规则执行的更高效; 在Hadoop的场景下,Drill是在提供了存储插件来处理分布式的文件和HBase.Drill也通过提供存储插件来集成了Hive的支持。 当用户通过Drill来查询文件或是HBase,他们可以直接执行,如果Hive有定义元数据的话,也可以通过Hive来执行。Drill集成Hive仅仅是为了元数据,Drill处理任何请求的时候都不执行Hive的查询执行引擎。
(翻译自Drill官网) 当您提交Drill查询的时候,客户端或应用程序会把查询以SQL语句的形式发送到Drill集群的一个Drillbit。Drillbit是在每个在线的Drill节点上运行的进程,它负责协调,规划和执行查询,并按照最大限度地实现数据本地化的原则在集群中分发查询。 下图描述了客户端,应用和drillbit之前的通信: 从客户端或应用端接收查询的那个drillbit会成为这个查询是的“接待员”,会负责驱动整个查询。这个”接待员“drillbit进程中有一个解析器,这个解析器解析这个SQL语句,应用一系列定制的规则,并把特定的SQL操作符翻译成相应的Drill能理解的逻辑操作符。这一系列逻辑操作符形成了一个逻辑计划。这个逻辑计划描述了为了得到查询结果需要做的工作,以及需要的数据源以及要进行的处理。 这个“接待员”drillbit 会将这个逻辑计划发送到一个基于开销核算的优化器,这个优化器会调整SQL操作符的顺序。优化器会应用各种各样的规则来做操作符和函数的对齐操作,并形成一个物理计划。最终就是,优化器将逻辑计划转换成了一个描述这个查询如何工作的物理计划。 一个“parallelizer"会将一条物理计划转换成若干条短语,这些短语我们称之为”一级碎片“和”次级碎片“。 Major Fragments 一个”Major Fragments“是这样一个概念,可以说是代表了Dril查询的一个阶段。一个”阶段(phase)“是Drill执行查询时必须执行的一个或多个操作单元。Drill会给每个Major Fragments 分配一个MajorFragmentID. 例如,为了计算两个文件的Hash,Drill可能就会创建两个主要阶段(两个Major fragments),第一阶段用来扫描文件 ,第二阶段则用来聚合数据。 Drill使用”Exchange Operator "来连接不同的Major fragments。一个"exchange"是指的数据的位置移动,或是将物理计划并行化的操作。一个“exchange"包含一个sender一个receiver,这使得数据可以在不同的节点间移动。 你可以在一个物理计划中用这种方式来参与Major fragments:你可以把物理计划导出到一个JSON文件中,手动修改它,并使用SUBMIT PLAN命令将这个json提交回Drill。你也可以在查询分析器中查看这些Major fragments,查询分析器可以通过Drill的WEB终端登入。请查询EXPLAIN和Query Profiles章节来获得更多信息。 Minor Fragments 每个Major Fragments 都可以并行化到一系列Minor Fragments;一个Minor Fragments是一个线程中运行的一个工作的逻辑单元。Drill中的一个逻辑工作单元,也被为一个”切片“。Drill 创建的执行计划,是由若干Minor Fragments组成的。Drill给每个Minor Fragments分配了一个MinorFragmentID; 在”接待员“drillbit中的”并行器“是负责从一个Major Fragment中创建出若干个Minor Fragments,做法就是将一个Major Fragment 打散成尽可能多的能在集群中同时运行的minor fragments. Drill在单独的线程内运行Minor Fragments,并且尽可能地快(这要看它依赖的上游数据)。Drill会把Minor Fragments归划到拥有数据本地化的那些节点上运行。如果做不到,Drill会在当前可用的Drillbit中使用那个流行的Round-Robbin算法进行分配。 Minor Fragments 包含一个或多个关系运算符。每个运算符执行一个操作,比如scan,filter,join,或是group by。每个运行符都有一个操作类型和一个操作ID(operationID).每个操作ID定义了它和它所从属的Minor Fragment和关系。请查阅”物理操作符“章节。 例如,当执行两个文件的Hash聚合操作时,Drill将第一个阶段(扫行扫描文件的阶段)打散成两个Minor frametns,每个minor fragments 包含一个扫描文件的扫描运算符。Drill把那个专司于进行数据聚合的阶段打散成4个minor fragments,四个中的每一个都包含 一个专门对数据做hash聚合的Hash 运算符。 你不能修改执行计划中的minor fragments的数量。不过,你可以在Drill web console中查看Query profiler并修改能够改变minor fragments行为的一些配置,比如修改最大切片数。请查阅”选项配置“章节。 Minor Fragments的执行 Minor Fragments可以作为叶子fragment,根fragment和中间fragment来运行。一棵执行树只能有一个根fragment.整棵执行树上的协调是通过从根fragment开始的数字来进行的,根节点的数字是0.数据流从叶子fragment到根fragment一个个地往下流。 根fragment运行在“接待员”Drillbit上,他接受查询,从数据表中读取元数据,重写查询,并将查询路由到执行树中的下一层。其他的fragments会成为叶子fragments或是中间fragments。 中间fragment会在数据可用,或是其他fragment将数据喂过来的时候开始执行。它们在数据上执行操作,并把它们往下传。它们也会把聚合过的数据传给根fragment,根fragment又会做进一步的聚合操作或者是把查询结果提供给客户端或是应用程序。 叶子fragment并行地扫表,或者是和存储层打交道,或是是读本地磁盘数据。叶子fragments把中间结果回传给中间fragments,中间fragments会接着在这些中间结果上各种并行操作。 Drill只会规划那些可以并发执行的fragments的查询,例如,如果一个集群只有20个切片,Drill会在那个Major fragment中规划最多20个minor fragments。Dril会乐观地假定它能并发地执行任务。一个Major fragments中的minor framents由于共同的上游数据依赖,会于同一时间开始执行。
(翻译自apache drill 官网) 架构总览 Apache drill是在大规模数据集场景下,可以低延迟地进行结构和半结构化/嵌套数据结构查询的一个分布式查询引擎。受到谷歌公司的Dremel的启发,Drill被设计出来以支持几千个节点和PB级别的数据规模下,支持交互响应级别的商务智能分析和查询。 Drill也适用到在大规模数据集场景下进行简单而迅速的查询.Drill能够查询像是JSON或是Parquet这种嵌套的数据,也能动态地发现schema.Drill并不需要一个中央的元数据库. 顶层架构(High-Level Architecture) Drill包含一个专门为了处理大规模数据的分布式执行环境。Apache Drill的核心是一个叫做“钻头”(drillbit)的服务,它负责从客户端接受请求,处理该查询,并将结果返回给客户端。一个drillbit服务可以在Hadoop集群中所有有需要的节点上安装和运行,形成一个分布式的集群环境。当drillbit运行在集群中的数据节点上时,drillbit可以查询执行过程中最大限度地使数据本地调用,而无需在网络上或是节点之间移动数据。Drill使用ZooKeeper来记录集群成员和健康检查信息。虽然钻工作在Hadoop集群环境中,Drill并不紧紧地与hadoop绑死,而是可以运行于任何分布式集群。Drill唯一的依赖是zookeeper. 请查阅Drill Query Execution Drill 客户端 你可以通过下面的客户端来访问drill: Drill shell Drill Web Console ODBC/JDBC C++ API 动态Schema发现 Drill并不需要一份数据schema或是类型定义就可以开始执行查询。Drill是分批次地开妈数据处理的。自描述的数据格式,像Parquet,JSON,AVRO,还有一些Nosql 数据库,格式描述是数据的一部分,Drill在处理的过程中会根据需求加以利用。 灵活的数据模型 Drill允许访问嵌套的数据属性,就好像它们是SQL列一样,并提供了直观的扩展以轻松地操作它们。从架构的角度来看,Drill提供了一个复杂的级联式的列式数据模型,用来描述复杂的,高度动态且不断变化的数据模型。在Drill里,关系数据被视为复合/多结构数据的一个简化处理。 去中央元数据设计 Drill不要求一个集中的元数据。你并不需要创建一个元数据库来存储表和视图,或依赖于一个有这种功能的元数据管理组件。Drill的元数据来源于那些跟源数据打交道的存储插件。存储插件能提供全部元数据中的一系列子区间(例如Hive),或是元数据的一部分(如HBase),或者就没有元数据(针对文件类)。去中央元数据意味着Drill不依赖于一个单一的Hive库,您可以一次查询多个Hive库,然后把结果与HBase的表或分布式文件系统中的文件信息组装起来。您也可以在Drill中使用SQL DDL语句来创建元数据,这些元数据就像传统的关系数据库中管理的一样。Drill的元数据也可以通过ANSI标准的INFORMATION_SCHEMA数据库来访问。 可扩展的设计 Drill在所有层都提供了一个可扩展的架构,包括存储插件,查询,查询优化/执行器以及客户端API层。您可以定制任意层来满足您的机构的特定需求,也可以把这一层延伸到更广泛的用途。Drill使用类路径扫描来查找和加载插件,并用最少的配置来添加额外的存储插件,功能和操作支持。