01-极简架构
Doris从设计上来说,融合了Google Mesa的数据存储模型、Apache的ORCFile存储格式、Apache Impala查询引擎和MySQL交互协议,是一个拥有先进技术和先进架构的领先设计产品,如图1所示。
▲图1 Doris技术分解图
在架构方面,Doris只有两类进程:一类是FE,可以理解为Doris的管理节点,主要负责用户请求的接入、查询计划的解析、元数据的存储和集群管理相关工作;另一类是BE,主要负责数据存储、查询计划的执行。这两类进程都是可以横向扩展的。除此之外,Doris不依赖任何第三方系统(如HDFS、Zookeeper等)。这种高度集成的架构设计极大地降低了运维成本。
FE节点包含Leader、Follower和Observer三种角色。默认一个集群只能有一个Leader,可以有多个Follower和Observer。其中,Leader和Follower组成一个Paxos选择组,如果Leader宕机,剩下的Follower会自动选出新的Leader,保证写入高可用。Observer同步Leader的数据,但是不参加选举。如果只部署一个FE,则FE默认就是Leader。
FE节点主要包括存储管理(Store Manager)模块、状态管理(State Store)模块、协调(Coordinator)模块、元数据(StoreMeta)模块和元数据缓存(StoreMeta Cache)模块。存储管理模块负责管理所有的元数据信息,包括数据库、表信息、tablet信息、tablet的副本信息等。存储管理模块还负责管理用户的权限信息(即用户的认证信息和授权信息)和数据的导入任务等。状态管理模块负责管理所有BE进程的存活状态信息、查询负载信息等非持久化信息,并提供发布订阅接口。协调模块负责接收用户发来的请求,然后进行语句解析、生成执行规划,根据当前集群的状态,对执行规划进行调度。元数据模块负责对元数据的读写,只有FE Leader拥有此权限。元数据缓存模块负责同步元数据,以供语句解析、生成执行规划,主要是Follower和Observer角色的权限。
BE节点可以无限扩展,并且所有BE节点的角色都是对等的。在集群足够大的情况下,部分BE下线不影响集群提供服务。BE节点主要由存储引擎(Store Engine)和查询执行器(Query Executor)组成。存储引擎负责管理节点本地的tablet数据,发送或者接收数据形成副本,定期合并更新多个版本的数据减少存储占用。存储引擎还负责接收来自查询执行器的数据读取需求和批量数据导入需求。一个查询在MPP集群中执行时,会拆成一个树状的执行树,这棵树的执行由Coordinator来协调执行,树的叶子节点也叫计划片断(PlanFragment),每一个PlanFragment分配给一个BE节点的查询执行器来执行,这就是查询执行器模块的作用。
02-使用简单
Doris不仅架构简单,开发和使用也非常简单。对一款OLAP数据库来说,性能不是数据库的全部,易用性才是决定是否持续使用的关键,Doris从系统设计之初就一直以用户的易用性作为出发点。
从数据分析的全周期来看,一般可以简单归纳成四个方面,从数据建模→数据导入→用户上手分析→持续使用以及维护升级,Doris的易用性无处不在。
在数据建模方面,Doris支持Aggregate、Unique和Duplicate三种模型,可以满足OLAP领域的各种应用场景。同时,Doris建表语句,相对于MySQL只增加了一些分布式系统所具有的特性,比如分布键、分桶数等。有过分布式数据库使用经验的用户非常容易理解和上手操作。
在数据导入方面,Doris提供多种数据导入方案(如图2所示),可以针对不同的数据源进行选择,同时在数据导入过程中提供原子性保证。不论是使用Broker Load进行批量导入,还是使用INSERT语句进行单条导入,都是一个完整的事务操作。导入事务可以保证一批次内的数据原子生效,不会出现部分数据写入的情况。
▲图2 Doris数据导入支持
同时,每一个导入作业都会生成一个Label,这个Label是在数据库内用于唯一区分一个导入任务。Label可以由用户指定,部分导入功能也会由系统自动生成。Label用于保证对应的导入作业仅能成功导入一次,一个成功导入的Label再次使用时,会被拒绝并报错Label already used。通过这个机制,数据消费侧可以实现At-Most-Once语义。如果结合上游系统的At-Least-Once语义,则可以实现端到端数据导入的Exactly-Once语义。数据导入流程如图3所示。
▲图3 Doris数据导入流程
在SQL开发方面,Doris支持标准的SQL语言,在方言方面向MySQL兼容。不论是简单的单表聚合、排序过滤操作,还是复杂的多表关联、子查询、窗口函数等,Doris都可以通过SQL轻松完成,极大地降低了用户的迁移和使用成本。Adhoc这类高吞吐的即席查询和库内ETL场景也是Doris的强项。Doris还能够支持复杂SQL语法,包括Grouping Set等高级语法功能,同时还可以通过UDF或UDAF来自定义拓展功能。在TB级别数据上,Doris可以部分代替Hive等离线系统的功能,使得用户在一套数据库中满足所有需求。
在工具方面,Doris在FE模块中实现了兼容MySQL协议,方便用户使用标准的MySQL客户端或各种语言的类库进行连接,对各种工具的支持都非常好。在数据库开发方面[3] [4] ,我们可以无缝使用DBeaver、DataGrip、Navicat等主流开发工具;在编程应用方面[5] [6] ,Doris完全支持MySQL的JDBC和ODBC接口,可以支持C、Python、Java、Shell等开发语言;在BI应用方面,Doris支持帆软BI、观远BI、永洪BI、Tableau等各种敏捷BI软件;在ETL调度方面,Doris支持Kettle、DolphinScheduler等主流软件。
在集群可靠性方面,Doris元数据使用内存存储+检查点+镜像日志文件的模式,使用BTBJE(类似于Raft )协议实现元数据的高可用性和高可靠性。Doris内部自行管理数据的多副本和自动修复,保证数据的高可用、高可靠性。在部分服务器宕机情况下,集群依然可以正常运行,数据也不会丢失。Doris部署无外部依赖,只需要部署BE和FE模块即可搭建一个集群。Doris支持在线更改表模式(加减列、创建Rollup ),不会影响当前服务,不会阻塞读、写等操作,因为这种操作是异步执行的。
在集群扩缩容方面,Doris基于自身的分布式管理框架,可以自动管理数据副本的分布、修复和均衡。比如对于副本损坏的情况,Doris会自动感知并进行修复。而对于节点扩缩容,仅需一条SQL命令即可完成,Doris会自动进行数据分片均衡,整个过程完全不影响系统服务,无须运维人员进行任何额外的操作。
在集群升级方面,Doris的升级方式却极其简单,只需要替换二进制程序,滚动重启集群即可。在设计上,Doris完全向前兼容,所以也可以通过灰度升级的方式进行新版本的验证和测试。而Doris本身的一些失败重试和故障路由功能也极大地降低了升级过程中发生的错误对业务的影响。
03-功能丰富
Doris提供了非常丰富的功能来帮助业务适应不同的应用场景。下面重点介绍一些Doris的特色功能。
首先是分区分桶裁剪功能。Doris支持两个层次的数据划分:第一层是Partition,支持Range和List的划分方式。第二层是Bucket分桶,将数据通过Hash进行水平划分,数据分片Tablet在集群中均匀打散。Doris数据分布示例如图4所示。
▲图4 Doris数据分布示例
利用分桶裁剪功能,Doris可以将查询固定到极少数分片上,从而显著降低单个查询对系统资源的消耗,提升集群整体的并发查询能力。在高并发查询场景,Doris单节点可以支撑上千QPS的查询请求。
其次是合理的缓存功能。Doris还支持SQL级别和Partition级别的查询缓存。其中SQL级别的缓存以SQL语句的Hash值作为Key,直接缓存SQL结果,非常适合更新频率不高,但是查询非常频繁的场景。而Partition级别的缓存会智能地将SQL结果中不同分区的结果数据缓存起来,之后的查询,可以利用已缓存分区的数据加上新分区实时查询的数据得到最终的结果,从而降低重复数据的实时查询需求,减少对系统资源的消耗。
再次,Doris支持Bitmap数据类型。这一数据类型利用位图来存储存储整型数据,并且可以通过位图进行一些集合类操作。Bitmap可以应用于高基数精确去重场景。传统的实时计算去重数据的算法,需要在内存中构建Hash表来进行数据去重,在基数非常高的情况下,会占用大量的内存。而使用Bitmap,可以将数值类型转换成位图上的0和1,从而极大地降低内存开销,并且对于去重计算,只需要将多个Bitmap求交集后计算1的个数即可,从而达到在有限的内存开销情况下,进行快速的高基数精确去重计算。
在用户画像场景中,使用Bitmap来存储用户ID,可以通过位图的集合运算快速获取不同标签组合的人群包。同时,Doris也内置了很多Bitmap相关的函数,用于计算漏斗、留存等。比如通过intersect_count()函数就可以方便地计算用户的留存情况。
最后是物化视图。物化视图也是Doris的核心特点之一。物化视图是将预先计算(根据定义好的SELECT语句)好的数据集,存储在一个对用户透明且有真实数据的视图表格中。物化视图主要是为了满足用户既能对原始明细数据的任意维度分析,也能快速对固定维度进行分析查询,在统一视角下对明细、聚合数据进行分析的需求。
在Doris中,用户可以使用明细数据模型存储明细数据,之后在明细数据上,选择任意维度和指标创建聚合物化视图,如SUM、MIN、MAX、COUNT等。Doris会保证明细表和物化视图中数据的完全一致。如果导入或删除物理表数据, 物化视图会自动更新,保证原始表和物化视图表的数据一致性。同时,物化视图对用户查询是透明的,Doris会自动根据查询语句中的模式,匹配到最合适的物化视图进行查询。通过物化视图功能,用户可以在一张表上统一明细和聚合模型,并且加速某些固定模式的查询响应。
Doris还支持基于主键的数据更新。通过Unique数据模型,用户可以对数据基于主键进行更新。在实现层面,Doris采用Merge-on-Read的方式提供更新后的数据,此外,用户还可以使用REPLACE_IF_NOT_NULL这种聚合方式,实现部分列更新的需求。针对Unique数据模型,Doris还支持友好的Update操作。
基于Unique模型,Doris还通过Marked Delete和Sequence Column等功能,可以实现对上游交易数据库更新数据的同步操作,并且不仅能够保证事务的原子性,还可以保证数据同步的顺序性。
04-开源开放
Doris还有一个特别重要的特点就是完全开源开放。Apache Doris作为Apache基金会的项目,遵守的就是Apache License 2.0。Apache License 2.0作为最主流的开源协议,被OSI认定为“受欢迎且被广泛使用或具有强大社区的许可证”(The following OSI-approved licenses are popular, widely used, or have strong communities)。
有关 Apache License 2.0的具体内容,可以在 Apache 官网查阅。简单来说,分发完全自由、允许项目代码被修改、允许作为开源或商业化软件再次发布 ,一旦授权永久有效,在修改代码或有源代码衍生的代码中需要带有原来代码的协议、专利声明等。这是对于任何商业化公司和开源用户都极其友好的协议。