如果你正在寻找一个既能处理海量数据,又能提供亚秒级查询响应的分析型数据库,那么Apache Doris很可能就是你的答案。它不像Hadoop生态那样需要复杂的组件堆叠,也不像传统数据仓库那样昂贵和笨重。Doris的设计哲学很直接:用一套系统解决海量数据的实时分析问题,并且要足够简单,让开发者能快速上手。我最初接触Doris是在一个用户行为分析的项目中,当时我们需要对每天TB级的日志数据进行即席查询,尝试了几种方案后,Doris在性能、易用性和运维成本上的平衡让我们最终选择了它。这篇文章,就是把我从零开始搭建、使用,到最终通过Python程序化操作Doris的实战经验,毫无保留地分享给你。无论你是数据分析师、后端开发,还是正在构建数据平台的技术负责人,这份指南都能帮你绕过我踩过的坑,高效地让Doris为你服务。
部署是使用任何数据库的第一步,也是最容易让人打退堂鼓的一步。好在Doris的部署相对清晰,尤其是单机测试环境。我们这里的目标是快速搭建一个可用于开发和功能验证的环境,而不是直接复刻生产集群的复杂配置。
1.1 系统要求与前置准备
在开始编译和安装之前,确保你的Linux环境满足基本要求。我推荐使用CentOS 7.x或Ubuntu 18.04及以上版本,内存至少4GB,磁盘空间预留20GB以上。最关键的是Java环境,Doris的FE(Frontend)节点依赖Java 8或Java 11。
除了Java,还需要安装一些编译工具。别小看这一步,缺少依赖会导致编译过程莫名其妙地失败。
注意:编译过程会消耗大量内存和CPU资源,建议在资源充足的机器上操作,或者适当增加交换分区(swap)以避免因内存不足导致编译进程被系统杀死。
1.2 源码编译与单机集群启动
Doris提供了预编译的二进制包,但为了获得更好的平台兼容性和对最新特性的支持,从源码编译是更推荐的方式。首先,我们从Apache的官方镜像获取源码。
接下来是编译。Doris使用Apache Maven进行Java部分(FE)的构建,使用CMake进行C++部分(BE)的构建。官方提供了一个便捷的脚本来处理整个流程。
这个过程可能需要30分钟到1小时,取决于你的机器性能。编译成功后,产出物会分别在和目录下。
现在,我们来启动一个最简单的单机伪集群(即FE和BE部署在同一台机器)。首先启动前端(FE)服务。
启动后,你可以通过日志文件查看启动状态,搜索 “thrift server started” 字样表示FE启动成功。默认的查询端口是9030,Web UI端口是8030。
接着启动后端(BE)服务。BE负责数据存储和计算。
BE启动后,需要将其添加到Doris集群中。使用MySQL客户端连接到FE(初始无密码)。
在MySQL客户端中执行以下命令添加BE节点:
你可以通过命令查看BE的状态,确保列为。至此,一个单机版的Doris集群就已经跑起来了。
集群跑起来只是开始,如何高效地组织数据才是发挥Doris威力的关键。Doris采用了MPP(大规模并行处理)架构,其数据模型和表设计直接决定了查询性能和存储效率。
2.1 理解Doris的数据模型
Doris主要支持三种数据模型:Duplicate Key模型、Aggregate Key模型和Unique Key模型。选择哪种模型,取决于你的业务场景。
- Duplicate Key模型:这是最简单的模型,允许重复的Key。它适用于无需预聚合的原始明细数据存储,例如日志流水、操作记录。建表时只需指定排序列(DUPLICATE KEY),这些列主要用于数据排序,提升范围查询性能。
- Aggregate Key模型:适用于需要实时聚合的场景,如PV、UV统计。在数据导入时,Doris会自动对Key相同的行,按照你指定的聚合函数(如SUM、MAX、MIN、REPLACE)进行聚合。这能极大减少存储空间并加速聚合查询。
- Unique Key模型:可以看作Aggregate Key模型的一个特例,它保证Key的唯一性,对于相同Key的后入数据,默认会覆盖先入的数据(REPLACE聚合)。非常适合需要实时更新的维度表或CDC(变更数据捕获)场景。
为了更直观地对比,我们来看一个表格:
2.2 表的创建、数据导入与查询
假设我们要分析一个电商网站的订单明细。我们创建一张使用Duplicate Key模型的表来存储最细粒度的数据。
这里有几个关键点:
- 指定了排序列,数据在磁盘上会大致按照这些列排序,对这类查询非常有利。
- 指定了数据分布方式。数据会根据的哈希值被分到10个桶(Bucket)中,每个桶会被调度到一个BE上。这是数据并行查询的基础。
- 在单机测试时设为1,生产环境通常设为3以保证高可用。
创建表后,我们来导入一些样本数据。Doris支持多种数据导入方式,这里演示最直接的和更适用于批量的。
对于从本地文件导入,可以使用命令进行Stream Load。假设我们有一个文件。
数据导入后,就可以进行查询了。Doris兼容MySQL协议,所以你可以使用熟悉的SQL。
虽然通过MySQL客户端操作很方便,但在数据应用开发中,我们更需要通过程序来与Doris交互。Python生态丰富,是数据领域的主流语言。与Doris交互,主要有两种方式:使用MySQL连接器和调用Doris的HTTP API。
3.1 使用MySQL Connector进行交互
这是最通用、最接近标准操作的方式。Doris的FE节点兼容MySQL协议,因此我们可以直接使用或这样的库。
首先安装连接器:
然后,你可以像连接任何MySQL数据库一样连接Doris:
这种方式简单直接,可以利用成熟的SQLAlchemy等ORM框架,也能方便地将查询结果与Pandas、NumPy结合进行数据分析。但它主要适用于查询和简单的DML(数据操纵语言),对于数据导入、作业管理等操作不够灵活。
3.2 调用Doris HTTP REST API进行高级操作
Doris提供了功能丰富的HTTP API,覆盖了数据导入、查询、作业管理、元数据查看等方方面面。这为我们构建自动化数据管道或集成到特定工作流中提供了极大的灵活性。最常用的是和。
使用库进行查询: 这种方式特别适合在无MySQL客户端环境或需要将查询服务封装成HTTP接口的场景。
使用Stream Load API进行数据导入: 这是将本地文件或程序生成的数据流高效导入Doris的推荐方式。它支持CSV、JSON等格式,并且是同步的,能立即得到导入结果反馈。
提示:参数在Stream Load中至关重要。Doris通过它来保证数据的Exactly-Once语义。即使用相同的label重复发起导入,只有第一次会成功,后续请求会被视为重复而跳过。这在构建ETL管道时,是防止数据重复的重要机制。
当数据量从测试的几百条增长到数亿甚至数十亿条时,查询性能可能会成为瓶颈。这时,合理的调优就至关重要。Doris的性能优化是一个系统工程,涉及表设计、查询编写、集群配置等多个层面。
4.1 表设计与数据分布策略优化
- 分区分桶(Partition & Bucketing)策略:这是Doris数据组织的核心。
- 分区(Partition):通常按时间(如天、月)进行范围分区。这能实现分区裁剪,查询时只扫描相关分区,极大减少数据读取量。例如,。
- 分桶(Bucketing):在分区内,数据通过哈希分桶到多个BE上。分桶列的选择应满足:1)高基数(值种类多),避免数据倾斜;2)常作为JOIN或GROUP BY的键。桶的数量需要权衡,太少不利于并行,太多会增加元数据开销。一般单个桶的数据量建议在100MB到1GB之间。
- 索引的智能使用:Doris内置了智能的索引机制,无需手动创建传统B树索引。
- 前缀索引:基于DUPLICATE/UNIQUE/AGGREGATE cursor 教程 KEY列的顺序,自动构建前缀索引。查询条件命中前缀索引的列时,能快速定位数据。因此,Key列的顺序应将高筛选性的、常作为查询条件的列放在前面。
- Bloom Filter索引:对于高基数列(如user_id, order_id)的等值查询过滤非常有效。可以在建表时对指定列启用:。
4.2 查询语句优化要点
即使表结构设计得很好,一个糟糕的查询也可能拖慢整个系统。
- 避免SELECT *:只查询需要的列。Doris是列式存储,读取不必要的列会造成额外的I/O。
- 利用分区裁剪:确保WHERE条件中包含分区列,让查询只扫描必要的分区。
- 注意JOIN顺序和类型:将数据量小的表放在JOIN的左侧。Doris支持Broadcast Join和Shuffle Join(Colocate Join更佳)。对于大表JOIN大表,确保它们的分桶列和分桶数一致,以启用Colocate Join,避免网络数据传输。
- 使用合适的聚合方式:对于Count Distinct,考虑使用或等近似聚合函数,它们在数据量极大时能大幅提升性能且精度可接受。
我们可以通过Doris的命令来查看查询的执行计划,这是性能诊断的利器。
查看的输出,重点关注:
- 字段:显示了实际扫描的分区数,确认分区裁剪是否生效。
- 字段:是否命中了物化视图(Rollup)。
- 字段:查询在多少个BE上并行执行。
- 是否存在节点:这表示数据需要在节点间传输,可能是Shuffle或Broadcast操作,对于大表可能是性能瓶颈。
4.3 监控、运维与高可用考量
对于生产环境,稳定性与可观测性必不可少。
- 监控指标:Doris提供了丰富的监控指标,可通过FE的Web UI(端口8030)的Metrics页面查看,或通过Prometheus抓取。关键指标包括:
- 查询延迟(Query Latency):
- 查询QPS:
- BE节点磁盘使用率:
- BE节点Compaction分数:(分数持续过高可能影响查询)
- 备份与恢复:定期备份元数据(通过备份目录的镜像)。数据备份可以通过Broker Load将数据导出到对象存储(如S3、OSS),或创建远程存储库(Repository)进行快照备份。
- 高可用部署:生产环境至少部署3个FE(1个Leader,2个Follower)和3个BE。FE之间通过BerkeleyDB Java Edition(BDBJE)进行选主和元数据同步。所有客户端应连接FE的VIP或通过负载均衡器,实现故障自动转移。
最后,我想分享一个实际项目中遇到的坑。我们曾有一个按天分区的表,每天数据量约1亿行。起初我们设置了10个桶。运行一段时间后,发现每天的数据导入时间越来越长,最终超时。通过监控发现,单个桶的数据量已经膨胀到超过10GB。这是因为我们的分桶列选择不当,导致数据严重倾斜,大部分数据都写入了少数几个桶。解决方案是重新评估分桶列,选择了基数更高的组合键,并将桶数增加到30个,之后导入性能恢复了正常。这个经历让我深刻体会到,在Doris中,往往是比绝对性能参数更优先的考量因素。
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/273898.html原文链接:https://javaforall.net
