官方文档
本次将主要从以下三部分介绍Apache Doris:
1.doris定位
2.doris整体架构
3.数据模型
1.Doris定位
我们首先看一下Doris整个的定位。
1. 数据仓库建设
2. OLAP/BI分析
3. 用户行为分析
4. 广告数据分析
5. 系统监控分析
Doris 的具体使用场景,可以接入多数据源,可以把数据源读到Doris里面来,然后在Doris里面对数据做各种的存储,以及做各种的多副本管理,基于Doris引擎进行数据处理。最后可以在上面接一个可视化工具,用来展示报表以及各种多维分析的检索的效果。这对于业务方在做可视化分析的时候效果是比较明显的。
简单来说,传统数据仓库能做的事Doris也能做,查询分析引擎能干的事Doris也能搞定。
Doris特点
1. 支持高并发点查询,支持明细和聚合查询
2. 支持离线批量导入和实时数据导入
3. 兼容MySQL协议和标准SQL
4. 支持Rollup Table和Rollup Table的智能查询路由
5. 支持较好的多表Join策略和灵活的表达式查询
6. 支持Schema在线变更
2.Doris整体架构
Doris 的整体架构和 TiDB 类似,借助 MySQL 协议,用户使用任意 MySQL 的ODBC/JDBC以及MySQL 的客户端,都可以直接访问 Doris。
1. Doris的架构很简洁,只有 FE(Frontend)、BE(Backend)两种角色
FE:主要负责元数据的管理、存储,以及查询的解析等;一个用户请求经过 FE 解析、规划后,具体的执行计划会发送给BE。
BE:则会完成查询的具体执行。BE 节点主要负责数据的存储、以及查询计划的执行。
FE 部分主要使用 JAVA,BE 部分主要使用 C++。FE,BE都可线性扩展。
FE 主要有三个角色,一个是 leader,一个是 follower,还有一个 observer。leader 跟 follower,主要是用来达到元数据的高可用,保证单节点宕机的情况下,元数据能够实时地在线恢复,而不影响整个服务。
- follower节点通过选举,其中一个 follower 成为 leader 节点,负责元数据的写入操作。当 leader 节点宕机后,其他 follower 节点会重新选举出一个 leader,保证服务的高可用。
- observer节点仅从 leader 节点进行元数据同步,不参与选举,不参与任何的写入,只参与读取。可以横向扩展以提供元数据的读服务的扩展性。
数据主要都是存储在 BE 里面,数据的可靠性由 BE 保证,BE 会对整个数据存储多副本。副本数可根据需求动态调整。
Doris查询数据快的原理
Distributed Logical Plan (分布式逻辑计划)
最早是借鉴了Impala的查询引擎,把它改造了一下引入到Doris里面形成一个分布式的查询引擎。把它查询规划所有的部分,都放到了一个FE里面,即在这个图中所看到的整个的逻辑规划,都会由FE来完成。FE来根据用户的查询生成一个完整的逻辑规划,然后这个逻辑规划最后生成一个分布式的逻辑规划,会发给整个集群去执行。
可以看一个具体的例子。上图这样一个查询,展示了最后生成的物理规划是什么样的。这个图就是展示了它的逻辑,就是说查询会生成几个算子,主要有扫描的算子,聚合的算子,还有Join的算子,最后再排序。右边就相当于对整个的算子的一个实际物理划分。这个规划途中单个方框我们称之为一个Fragment, Fragment由单个BE节点执行,Fragment之间的数据交换通过RPC来完成。整个物理规划执行完之后,由FE把数据收集起来反馈给用户。
3.数据模型
Doris 的数据模型分为4类
1. Aggregate 聚合模型
2. Uniq 唯一主键模型
3. Duplicate 明细模型
4. ROLLUP模型
1. Aggregate 聚合模型
应用场景:因为Doris它最早是给凤巢的一个广告报表做的,广告报表有一个很大的特点,就是它只关心统计分析的结果,而不太关心明细的数据,所以Doris最早一代的数据模型,是一个聚合的模型。
如果转换成建表语句则如下
CREATE TABLE IF NOT EXISTS example_db.expamle_tbl ( `user_id` LARGEINT NOT NULL COMMENT "用户id", `date` DATE NOT NULL COMMENT "数据灌入日期时间", `city` VARCHAR(20) COMMENT "用户所在城市", `age` SMALLINT COMMENT "用户年龄", `sex` TINYINT COMMENT "用户性别", `last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 00:00:00" COMMENT "用户最后一次访问时间", `cost` BIGINT SUM DEFAULT "0" COMMENT "用户总消费", ) AGGREGATE KEY(`user_id`, `date`, `timestamp`, `city`, `age`, `sex`) ... /* 省略 Partition 和 Distribution 信息 */
表中的列按照是否设置了 AggregationType,分为 Key (维度列) 和 Value(指标列)。没有设置 AggregationType 的,如 user_id、date、age ... 等称为 Key,而设置了 AggregationType 的称为 Value。
当我们导入数据时,对于 Key 列相同的行会聚合成一行,而 Value 列会按照设置的 AggregationType 进行聚合。
AggregationType 目前有以下四种聚合方式:
1. SUM:求和,多行的 Value 进行累加。
2. REPLACE:替代,下一批数据中的 Value 会替换之前导入过的行中的 Value。
3. MAX:保留最大值。
4. MIN:保留最小值。
经过聚合,Doris 中最终只会存储聚合后的数据。换句话说,即明细数据会丢失,用户不能够再查询到聚合前的明细数据了。
AGGREGATE KEY 数据模型中,所有没有指定聚合方式(SUM、REPLACE、MAX、MIN)的列视为 Key 列。而其余则为 Value 列。定义列时,可参照如下建议:
1. Key 列必须在所有 Value 列之前。
2. 尽量选择整型类型。因为整型类型的计算和查找比较效率远高于字符串。
3. 对于不同长度的整型类型的选择原则,遵循 够用即可。
4. 所有列的总字节长度(包括 Key 和 Value)不能超过 100KB。
2. Uniq 唯一主键模型
应用场景:用户更关注的是如何保证 Key 的唯一性,即如何获得 Primary Key 唯一性约束。因此,我们引入了 Uniq 的数据模型。该模型本质上是聚合模型的一个特例,也是一种简化的表结构表示方式。
这是一个典型的用户基础信息表。这类数据没有聚合需求,只需保证主键唯一性。(这里的主键为 user_id + username)。那么我们的建表语句如下: CREATE TABLE IF NOT EXISTS example_db.expamle_tbl ( `user_id` LARGEINT NOT NULL COMMENT "用户id", `username` VARCHAR(50) NOT NULL COMMENT "用户昵称", `city` VARCHAR(20) COMMENT "用户所在城市", `age` SMALLINT COMMENT "用户年龄", `sex` TINYINT COMMENT "用户性别", `phone` LARGEINT COMMENT "用户电话", `address` VARCHAR(500) COMMENT "用户地址", `register_time` DATETIME COMMENT "用户注册时间" ) UNIQUE KEY(`user_id`, `user_name`) ... /* 省略 Partition 和 Distribution 信息 */
即 Uniq 模型完全可以用聚合模型中的 REPLACE 方式替代。其内部的实现方式和数据存储方式也完全一样。
3. Duplicate 明细模型
应用场景:数据既没有主键,也没有聚合需求。因此,我们引入 Duplicate 数据模型来满足这类需求。
建表语句如下: CREATE TABLE IF NOT EXISTS example_db.expamle_tbl ( `timestamp` DATETIME NOT NULL COMMENT "日志时间", `type` INT NOT NULL COMMENT "日志类型", `error_code` INT COMMENT "错误码", `error_msg` VARCHAR(1024) COMMENT "错误详细信息", `op_id` BIGINT COMMENT "负责人id", `op_time` DATETIME COMMENT "处理时间" ) DUPLICATE KEY(`timestamp`, `type`) ... /* 省略 Partition 和 Distribution 信息 */
这种数据模型区别于 Aggregate 和 Uniq 模型。数据完全按照导入文件中的数据进行存储,不会有任何聚合。即使两行数据完全相同,也都会保留。 而在建表语句中指定的 DUPLICATE KEY,只是用来指明底层数据按照那些列进行排序。在 DUPLICATE KEY 的选择上,我们建议适当的选择前 2-4日志时间和日志类型列就可以。
4. ROLLUP模型
在 Doris 中,将用户通过建表语句创建出来的表成为 Base 表。Base 表中保存着按用户建表语句指定的方式存储的基础数据。
在 Base 表之上,我们可以创建任意多个 ROLLUP 表。这些 ROLLUP 的数据是基于 Base 表产生的,并且在物理上是独立存储的。
ROLLUP 表的基本作用,在于在 Base 表的基础上,获得更粗粒度的聚合数据。
下面用示例详细说明在不同数据模型中的 ROLLUP 表及其作用。
1. 获得每个用户的总消费
在此基础上,我们创建一个 ROLLUP
SELECT user_id, sum(cost) FROM table GROUP BY user_id;
Doris 会自动命中这个 ROLLUP 表,从而只需扫描极少的数据量,即可完成这次聚合查询。
示例:获得不同城市,不同年龄段用户的总消费、最长和最短页面驻留时间 紧接示例1。我们在 Base 表基础之上,再创建一个 ROLLUP:
当我们进行如下这些查询时:
SELECT city, age, sum(cost), max(max_dwell_time), min(min_dwell_time) FROM table GROUP BY city, age;
SELECT city, sum(cost), max(max_dwell_time), min(min_dwell_time) FROM table GROUP BY city;
SELECT city, age, sum(cost), min(min_dwell_time) FROM table GROUP BY city, age;