写在前面
本文主要对Doris进行整体性介绍,在了解Doris的发展、核心特性,整体架构的基础上,结合网上资料对比了Doris和OLAP数据库的异同性,最后总结了Doris的使用现状。总的来说,除了Doris本身的特性以外,Doris从最初的为了解决广告流量的增加到最后沉淀出一款开源的数据分析库产品的整个发展是值得借鉴和思考的。
1. Doris是什么
Doris是一个现代化的MPP架构的分析型数据库产品,由百度大数据部门开发。在百度内部支持超过200个产品线,集群规模上千台,数据规模超过10PB,经受长期的生产验证。
2. Doris发展历史节点
- 时间节点:2008
遇到问题:1、百度本身流量、广告流量增加;
2、大规模数据使得MySQL的查询、读取性能降低
3、现有数据存储的开源产品啥,Hbase的导入只能达到2000条/秒
解决方式:产生Doris1,改进方面如下:
1、Doris的数据模型分为key列,value列。一条数据的key列包括:用户ID、时间、地域、来源等维度信息,value列包
括:展示次数、点击次数、消费额等。
假定聚合的时间维度最小粒度是小时,那同一小时多次导入的数据是可以被合并为一条,相比MySQL,Doris1要扫描
的数据条目降低很多。
2、Doris1将MySQL逐条插入改成了批量更新,并且通过外围模块将同一批次数据进行排序以及预聚合。排序后的数据在
查询的时候可以起到聚集索引的作用,从而提高查询性能。
3、提供了天表、月表这种类似物化视图的功能。
最终效果:完全解决了MySQL Sharding遇到的问题,10月份上线,完美地支撑了广告系统报表需求。 - 时间节点:2009
遇到问题:Doris1实现的时候只为了满足凤巢的业务需求,并没有兼顾其他的应用需求。
解决方式:1、将Doris1进行通用化改造,包括自定义schema等,使Doris能够应用于其他产品。
2、进行一些优化来以此提升系统的查询、存储性能。
最终效果:Doris2完成后,上线百度统计,助力百度统计为当时国内规模最大,性能、功能最强的统计平台。 - 时间节点:2010
遇到问题:1、Doris2对于长时间跨度的查询请求、以及大客户的查询请求等无法实现很好的查询性能。
2、Doris2在运维上需要停服后手动操作,使得不仅用户体验差,还会增加运维成本。
3、Doris2不是高可用系统,机器故障问题会影响服务的稳定性。
解决方式:1、Doris3架构设计如下图所示。DT(Data Transfer)负责数据导入、DS(Data Searcher)模块负责数据查询、
DM(Data ;Master)模块负责集群元数据管理、Armor分布式key-value引擎负责数据存储。Doris3依赖Zookeeper存储元数据,
进而保证整个系统能够做到无故障单单点。
2、Doris3在数据分布方面引入了分区的概念。数据先按照时间进行分区,在同一个分区里面,数据会根据用户ID再进行
分区,从而保证多台机器可以同时处理一个用户的数据。对于单一分区内部用户数据可能过大的情况,Doris3将单个分区内
大用户的数据进行拆分,导入到过分片中,保证每个片内用户的数据总量最高是有限的。
3、Doris3在日常运维Schema Change,以及扩容、缩容等方面都做了针对性设计,使其能够自动化进行,不依赖线上人
工操作。
最终效果:Doris3成功解决大客户查询的问题。公司内部的需求,由Doris3来承担支持。 - 时间节点:2012
遇到问题:1、Doris3只支持单表的统计分析查询,不能满足业务进行多维分析的需求。具体表现在缺少通用SQL的支持,Doris3在更加灵
活的多维分析场景上显得力不从心。
解决方式:1、Doris3采用MySQL Storage Handler的方式来扩展Doris3,从而保证能够支持业务的多维需求。具体来说,Doris Handler
(类似MyISAM、InnoDB)将Doris3伪装成一个MySQL的存储后端,不仅能利用MySQL对SQL的支持,也能利用上Doris3对
于大数量的支持。为了减轻MySQL的计算压力,Doris3应该MySQL的BKA(Batched Key Access)和MRR(Multi-Range
Read)机制将计算下推到Doris3完成。
最终效果:通过MySQL+Doris3这个方案,百度Insight团队为PS、LBS、WISE等产品线提供了百度内部第一个OLAP分析服务平台。
OLAP Engine项目的启动
key-value存储引擎的弊端日益显露。具体表现在以下几点:
1、key-value系统只能读取全key,全value,分析报表并不需要全列,因此带来不必要的开销。
2、Doris3借助复杂的作业管理在引擎外部完成merge工作,既不简洁,也不高效。
3、Doris3通过添加版本号的方式保证数据的原子性,查询的时候则需要过滤版本。
4、key-value系统无法感知数据内容,只能使用通用的算法压缩,使得数据压缩效率不高
OLAP Engine在底层引擎上突破,最大的特点包括以下几点:
1、引擎端原生就支持Schema,并且所有的列分为key列,value列。查询时,无需加载全部列,减少不必要的开销。
2、独特的数据模型。value类支持聚合操作,包括sum、min、max等。引擎导入方式类似LSM Tree,在引擎后台进行merge的同时,就能
够将相同的数据中的value字段按照对应的操作进行聚合。
3、数据批量导入,原子生效。在查询的时候只是在初始化的时候来确定读取哪个文件,从而只读取有效的版本。
4、行列存储。多行数据存储在一个block块内,block块内相同列的数据一同压缩存放,从而可以根据数据特征大幅提高数据压缩效率。
- 时间节点:2013
遇到问题:1、SQL的复杂性,使得大量计算都需要在MySQL中完成,此时MySQL的计算能力成为瓶颈。此时,分布式查询引擎也在发
展,如Impala、Tajo、Presto等。
解决方式:1、选择Impala作为查询引擎,主要原因是性能较高,并且BE的C++语言和已有系统一致。
最终结果:新产品命名为PALO,意为玩转OLAP。PALO1架构如下所示。DM负责管理元数据、数据的分布、分片副本管理等内容,DM本
身没有状态,元数据内容都存储在MySQL中。FE负责接收用户的查询请求,并且进行查询规划解析,BE负责数据存储,以及进
行具体的查询执行。
- 时间节点:2015
遇到问题:1、核心主要针对PALO1进行优化,具体表现在PALO1模块数目多、外部依赖MYSQL等。
解决方式:1、PALO2结构图如下。PALO2只存在2种模块:FE、BE。FE一方面负责管理、存储元数据,另一方面FE还负责与用户交互,
接受用户查询,对查询规划,监督查询执行,并将查询结果返回给用户。BE与PALO1功能一致,但是增加了存储引擎。
最终效果:通过PALO2的工作,系统架构本身变得相当简洁,并且不需要任何依赖。
… - 如何认识更广阔的世界?
Palo于2017年正式在GitHub上开源,并且在2018年贡献给Apache社区,并将名字改为Apache Doris(incubating)进行正式孵化。
3. Doris核心特性
-
现代化MPP架构
MPP,即messively paraller processing,大规模并行处理。通常来说,就是将任务分给不同的节点进行并行计算,最终将结果汇总返回。
MPP架构特点:
1、多节点:节点间数据不共享,只能通过网络协同。通信效率一定程度上决定了查询效率。
2、节点独立:每一个节点都有自己的CPU、磁盘、总线。
3、并行计算:数据根据hash算法分散到不同的服务器上,在任务执行时也是分散到不同的机器上执行完成后汇总返回。
4、CAP:首先保证C(一致性)、然后保证A(可用性)、最后考虑P(分区容忍性)。
架构特点产生的劣势:
1、依赖网络:集群机器协同工作依赖网络,网络出错将导致不可用。
2、扩展性差:业务数据分配到了不同的节点,节点过多,元数据的管理则相对困难。 -
亚秒级查询返回延时:任务分发到不同的节点并行处理,提高了查询效率。
-
支持标准SQL语言,兼容MySQL协议。
-
向量化执行器
1、向量化执行引擎可以减少节点间的调度,提供CPU的利用率。
2、列存储结构,使得可以通过向量化执行引擎进行优化,同时更好地进行数据压缩,提搞压缩比。 -
高效的聚合表技术:用户最终查询到的都是聚合后的数据。
数据聚合的三个阶段:
1、ETL阶段:导入一批次的数据到目的端时,即Extra(导入)->Transform(转换)->load(存储)过程中
2、Compaction阶段:底层在对数据进行Compaction时
3、查询:用户执行查询时 -
新型预聚合技术Rollup:对于查询会有部分聚合的处理动作,可以参考with rollup语法。
-
高性能、高可用、高可靠
-
极简运维,弹性伸缩:部署轻量,不依赖外部其他东西
4. Doris架构
Doris借鉴了Google Mesa数据模型,改造Apache Impala,基于Apache ORCFile自研存储引擎。
Doris之所以需要借鉴这三项技术,主要基于如下原因:
- Mesa是一种高度可扩展的分析数据存储系统,用于存储与Google的互联网广告业务有关的关键测量数据。可以满足许多存储需求,但本身不提供SQL查询引擎。
- Impala是一个优秀的MPP SQL查询引擎,但是缺少完美的分布式存储引擎。
- 自研列式存储:存储层对存储数据的管理通过storage_root_path路径进行配置,路径可以是多个。存储目录下一层按照分桶进行组织,分桶目录下存放具有的tablet,按照tablet_id命名子目录。
不过需要注意的是,在Doris的架构设计中,并不是简单地进行了整合,底层也进行了修改。
整体架构
Doris的架构设计很简洁,主要涉及FE(Frontend)、BE(Backend)两种角色、两类进程。不依赖于外部组件,方便部署和运维。FE、BE都可以线性扩展。
- FE,Java语言开发,主要完成以下三方面工作:
1、Doris系统的元数据管理(存储、维护集群元数据)
2、负责接收、解析查询请求,规划查询计划,调度查询执行,返回查询结果
3、节点调度,在导入流程中主要负责导入plan生成和导入任务的调度工作
FE又分为三种角色:
1、Leader和Follower:主要是用来保证元数据的高可用,保证单节点宕机的情况下,元数据能够实现地在线恢复,而不影响整个服务。Leader是基于paxos协议选举出来的(负责读写)。
2、observer只是用来扩展查询节点,就是说如果在发现集群压力非常大的情况下,需要去扩展整个查询的能力,那么可以加observer的节点。observer不参与任何的写入,只参与读取(读)。
注:参与选举的Follower不需要过多。 - BE,C++语言开发,Doris系统的计算和存储节点,执行SQL计划等。在导入流程中主要负责数据的ETL和存储。
- MYSQL Client
Doris借助MySQL协议,用户使用任意MySQL的ODBC/JDBC以及MySQL的客户端,都可以直接访问Doris。 - Broker
Broker为一个独立的无状态进程。封装了文件系统的接口,提供Doris读取远端存储系统中文件的能力,包括hdfs、s3、bos等。
表设计层面
-
Doris支持两层数据划分
第一层是Partition分区,支持Range的划分方式,是数据导入和备份灰分的最小逻辑单位。可以通过按照时间维度或者数据的冷热程度进行划分,从而利用分区裁剪的减少数据的访问量。第二层是Distribution分桶,支持Hash的划分方式,是数据复制和均衡的最小物理单位。通过对分桶键进行hash以后均匀分布在BE上。在对桶的数量进行选择的时候,尽量保证最后能够使得tablet控制在100MB~1GB之间。
存储引擎层面
- 列式存储。下表对比了行存储方式和列存储方式各种的优缺点。
行存储 | 列存储 | |
---|---|---|
写入 | 一次性完成写入,性能高效 | 把行拆成列保存,写入次数增多 |
查询 | 读取整行数据时,依顺序读取,性能高 | 读取列的时候,无需读取无关列,效率更高 |
压缩 | 效率低 | 同一类型的数据存放在一起,对压缩算法更加友好,压缩比较高 |
举例 | Text File、Sequence File | ORC、Parquet |
Clickhouse官网给出的行列存储,数据读取性能对比图
行存储
列存储
- 索引结构。在OLAP领域,通常建立稀疏索引,Doris整体上将索引分为两种,智能索引和手动索引,两者的区别在于是否由存储引擎自动导入。智能索引包括前缀稀疏索引、MIN MAX索引、BloomFilter索引等,手动索引包括倒排索引。
1、前缀稀疏索引是建立在排序结构上的索引,可以帮助我们快速定位到起始行。
2、MIN MAX索引是建立在Segment和Page级别的索引,对于Page中的每一列,都会记录器最小值和最大值,在进行等值或范围查询时候,可以通过MINMAX索引快速过滤掉不需要读取的行。
3、BloomFilter索引由用户决定是否创建。在对某列使用BloomFilter过后,会在page级别创建该列的BloomFileter,由于BloomFilter是一种使用固定空间的位图来快速判断一个值是否存在的数据结构,使得这种索引非常适用于高基数列上的等值查询,比如UUID。
4、倒排索引是一种基于bitmap的索引结构,其key是实际的列植,value是改值在文件中的位置,通过倒排索引可以很快定位到对于的行号,进行快速取数。这种索引比较适合在基数较低的列上进行等值查询的场景。
计算引擎层面
- MPP执行模型。大数据领域常用的执行模型包括Scatter Gather模型、Map Reduce模型、MPP执行模型。Scatter Gather模型使用单间汇聚,无法很好完成大表join,高基数聚合,其代表系统包括Clickhouse、ElasticSearch。Map Reduce任务之间需要等待,中间数据需要落盘,但是使用任务级别的调度,可以很好的进行中断恢复,其代表模型包括MapReduce(落地实现的系统)、Spark。MPP执行模型任务之间流水线执行,数据在内存中传输,延时更短,对于毫秒级别查询更有优势,但是失去了断点续传的功能,代表系统包括Greenplum、Doris、Impala。
- 向量化执行。在依托列式内存布局的前提下,按照列的方式对表达式计算和节点计算,通过利用CPU的SIMD指令集加快运行速度。基于单指令流多数据流的方式,使得CPU可以一次计算一个值到一次计算一组值,以Filter为例,和原先的行存储逻辑相比,减少了分支判断的次数。
- 聚合优化,自适应两层聚合。Doris将聚合阶段分为Local Aggregate和Final Aggregate两个阶段。Local Aggregate,本地部分聚合,会在数据节点先进行一次本地聚合,从而减少发送到Final Aggregate的数量。Final Aggregate,全量聚合,会将相同的key聚合到同一个节点,进行最终的聚合计算。聚合算子是一种阻塞型的算子,如果在Local Aggregate阶段发现数据聚合效果很低,即无法有效降低需要传输数据时,Doris会通过自适应机制,将算子转化为非阻塞式算子,直接将数据读取后发送懂Final Aggregate,从而避免发生不必要的阻塞等待时间。
5. 横向对比
本节从整体上对比了Doris和现有的OLAP数据库的差异性,然后从细节上对比了Doris和ClickHouse的差异性。
Doris和OLAP数据库对比
OLAP | 优点 | 缺点 | 外部依赖 | SQL支持 | 运维成本 | 适用场景 | 存储引擎 |
---|---|---|---|---|---|---|---|
ClickHouse | 高效列式存储 单节点性能强劲 向量化查询 保留明细数据 | 运维成本较高 在线扩展能力稍显不足 | 中 | 非标准 | 高 | 全面 | 纯列式OLAP |
Druid | 实时摄取 列式存储 位图索引 高并发 | 适用门槛高 运维复杂 仅支持聚合查询 | 中 | 非标准 | 很高 | 局限 | MOLAP |
TiDB | HTAP 同时支持明细和聚合查询 高度兼容MySQL | OLAP能力不足 | 低 | 兼容MySQL协议 | 低 | 全面 | HTAP |
Kylin | 预聚合之后多维分析性能强悍 支持超大规模数据 支持标准SQL易用性好 | 1.x、2.x、3.x依赖Hadoop 仅支持聚合查询 | 高 | SQL标准 | 中 | 局限 | MOLAP |
Doris | 主键更新 高效Rollup 高并发和高吞吐可选 支持聚合和明细查询 没有外部依赖 | 生态成熟度不足 | 低 | 兼容MySQL协议 | 低 | 全面 | ROLAP |
Doris和ClickHouse对比
- ClickBench
ClickBench是由ClickHouse社区开发的,适合于OALP系统进行性能测试,ClickBench的数据最迟是通过从一周的点击数据中抽取1/50,再从中抽取前10亿、1亿、1000万条记录来错则是集合。下图跑分截取于2023年10月22日,测试过程中以冷热启动方式不同作为对比指标。
cold run:系统启动或者数据库刚刚加载时运行性能测试,可以用来表征数据库初始化的开销和性能。cold run中,SelectDB第一,ClickHouse第二,StarRocks第三。
hot run:数据库已经运行一段时间,并且缓存已经被有效填充后运行性能测试,可以用来评估数据库在日常负载下的性能,从而更好了解用户实际体验。hot run中,测试机都是c6a.metal, 500gb gp2,ClickHouse第一,StarRocks第二。
- 详细对比
类别 | Doris | ClickHouse | 备注 |
---|---|---|---|
部署和运维 | 维护FE和BE两个组件即可; 有较多的SQL命令可以协助运维 | 维护Server、Zookeeper、CHproxy三个组件; 需要修改配置并下发到各个节点上 | 两者更改配置文件都需要依赖Ansible或者SaltStack批量更新; 都可以热更新而不用重启节点 |
多租户管理 | Doris 具有复杂的基于角色的访问控制,它允许在数据库、表、行和列级别进行细粒度的权限控制 | ClickHouse的权限和Quota的粒度更细,可以很方便的支持多租户使用共享集群,包括设置查询内存限制、用户内存限制等 | 多租户的方案,对发展中业务非常友好,可以共享集群资源,快速动态调整配额 |
集群迁移 | 通过内置命令backup/restore将数据和元数据进行备份,并且可以按照分区实现增量备份,降低备份成本 | 数据量大通过自带copier工具实现数据拷贝,需要配置很多信息;数据量小可以通过SQL命令实现 | ClickHouse官方对实现其他存储介质的备份和恢复的推荐是采用文件系统的snapshot实现 |
扩容/缩容 | Doris支持集群的在线动态扩容缩容,数据均衡的粒度是tablet | ClickHouse的扩容缩容复杂且繁琐,目前无法实现自动在线操作 | |
分布式能力 | Doris能自动复制具有自动灾备的能力,服务挂了可以自动重启,小范围的节点宕机不会影响集群对外的服务,但宕机后数据均衡过程会消耗集群资源,引发短时间的负载过高 | ClickHouse依赖Zookeeper来实现数据的高可用,Zookeeper带来额外的运维复杂性的同时也有性能问题 | 在分布式能力这块,Doris在内核侧已经实现,使用的代价更低;而ClickHouse需要依赖于外部配套的措施去保障,使用成本较高 |
事务支持 | Doris提供了导入的事务支持,可以保证导数的幂等性 | Doris提供了导入的事务支持,可以保证导数的幂等性 | DDL操作两者都是异步的,但是Doris能保证各个节点元数据的一致性 |
数据导入 | Doris中有RoutineLoad、BrokerLoad和StreamLoad等丰富内置的导数方式 | ClickHouse中并没有后台导数任务这一概念,它更多的是通过各种引擎去连接到各种存储系统中 | ClickHouse可以导入本地表,而且没有事务的限制,导入性能差不多是节点磁盘写入性能,而Doris的导数受限于只能分布式表的导入,导入性能差一些 |
使用成本 | Doris使用成本低,是一个强一致性元数据的系统,查询SQL的标准兼容好无需额外的工作 | ClickHouse则需要做较多工作,故障节点的容忍度较低 | 在大规模实施ClickHouse时,需要研发一个比较好用的运维系统的支持,处理大部分的日常运维工作 |
代码框架 | Doris的代码风格整体质量是比较高的,风格统一,如果要在Doris上做二次开发,则需要熟悉Java或C++ | ClickHouse对二次开发更加友好,技术栈单一,且测试框架完善,模块间互相依赖关系相对较小 | |
性能测试 | 多表性能Doris优势更明显,特别是复杂Join和大表Join大表的场景 | 单表性能ClickHouse更好,无论是查询延时还是并发能力 |
总的来说,Doris源自在线广告系统,偏交易系统数据分析;ClickHouse起源于网站流量分析服务,偏互联网数据分析,但是这两类场景这两个引擎都可以覆盖。如果说两者不那么强的地方,ClickHouse的问题是使用门槛高、运维成本高和分布式能力太弱,需要较多的定制化和较深的技术实力,Doris的问题的生态成熟度不如ClickHouse。
6. 使用场景及现状
截止目前, Apache Doris 已经在全球超过 2000 家企业的生产环境中得到应用,在中国市值或估值排行前 50 的互联网公司中,有超过 80% 长期使用 Apache Doris,包括百度、美团、小米、京东、字节跳动、腾讯、网易、快手、微博、贝壳等。同时在一些传统行业如金融、能源、制造、电信等领域也有着丰富的应用。总体来说,Doris场景的使用场景如下:
- 报表分析:面向企业内部分析师和管理者的报表、实时看板等。著名的电商公司京东在广告报表中使用 Apache Doris ,每天写入 100 亿行数据,查询并发 QPS 上万,99 分位的查询延时 150ms。
- 即席查询:面向分析师的自助分析,查询模式不固定,要求较高的吞吐。米公司基于 Doris 构建了增长分析平台(Growing Analytics,GA),利用用户行为数据对业务进行增长分析,平均查询延时 10s,95 分位的查询延时 30s 以内,每天的 SQL 查询量为数万条。
- 统一数仓构建:简化繁琐的大数据软件栈。海底捞基于 Doris 构建的统一数仓,替换了原来由 Spark、Hive、Kudu、Hbase、Phoenix 组成的旧架构,架构大大简化。
- 数据湖联邦查询:通过外表的方式联邦分析位于 Hive、Iceberg、Hudi 中的数据,在避免数据拷贝的前提下,查询性能大幅提升。