ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

从Presto迁移到Doris:安装部署、集群规划与调优实战

从Presto迁移到Doris:安装部署、集群规划与调优实战 凌晨两点我盯着屏幕上那行“Column order_id cannot be resolved”的报错Presto集群的元数据缓存又没跟上。那一刻我决定下一套报表平台直接搭在Doris上。如果你也在Presto和Doris之间举棋不定或者正准备做Doris安装部署和集群部署这篇内容可以帮你少走不少弯路。我会从单机跑起来开始一直讲到生产集群的规划、迁移SQL时遇到的“missing”问题以及运行半年后沉淀下来的调优清单。1. 先从一次“missing”报错说起为什么我不再让Presto跑核心报表1.1 一次凌晨报表任务的完整排查链路那是一个常规的日报任务凌晨两点由Presto集群调度执行。SQL本身不复杂从一张订单明细表里按城市分组统计GMV关联一张用户维度表取注册时间。问题出在关联之后Presto报了一个让我当时很头疼的错误——Column order_id cannot be resolved。我当时的排查链路是这样的第一步检查SQL文本。SELECT里确实没有引用order_id误写不成立。第二步单独查字段。SELECT order_id FROM 订单表 LIMIT 1能跑通说明底层表结构里有这一列。第三步怀疑是表结构变更。去查元数据管理服务发现这张表在凌晨一点多刚做过一次schema更新新增了一个字段而Presto连接器缓存的元数据没有及时刷新。第四步在Presto端刷新元数据缓存重新执行任务恢复。整个过程花了大概四十分钟。问题本身不复杂但这类“元数据不同步导致的missing”在Presto联邦查询架构里非常折磨人查询引擎、元数据服务、底层存储是三个独立的系统任何一个环节缓存滞后你都会看到莫名其妙的列或表解析失败。后来我把同一套报表迁到了Doris上。同样的SQL在Doris里直接跑通不会再出现“某个列突然消失”的情况。因为Doris是存储与计算一体的OLAP数据库元数据和数据在同一个集群里建表、删列、查询走的是同一套MySQL协议入口不存在连接器缓存漂移的问题。1.2 Doris的定位它和Presto、ClickHouse的关键差异很多人把Doris和Presto放在同一个篮子里比较其实它们是两种不同的东西。Presto是一个分布式SQL查询引擎本身不存数据。它通过连接器去读Hive、HDFS、S3、MySQL等各种数据源优势是灵活适合做联邦查询、数据湖分析。劣势也很明显没有自己的存储查询性能取决于下游数据源的组织方式元数据链路长容易出现前面说的“missing”类问题。Doris则是完整的MPP分析型数据库。它有自己的列式存储引擎、向量化执行引擎、CBO优化器同时兼容MySQL协议。数据导入之后查询直接在Doris内部完成不需要跨系统拉数据。ClickHouse是另一个常被拿来对比的列存数据库。ClickHouse单机查询性能非常强但在集群运维、join能力、精确去重这些方面团队需要付出的精力更多。Doris在分布式join、高并发点查、多表关联这些场景上更均衡一些而且建表、导入、权限管理都做得比较完善。我用一张表把三者的差异理顺维度PrestoDorisClickHouse是否自带存储否依赖外部数据源是列式存储是列式存储元数据一致性多系统协同易缓存延迟存储计算一体一致性高存储计算一体一致性较高SQL兼容ANSI SQL但分数据源方言MySQL协议习惯成本低SQL方言较特殊适用场景数据湖、联邦查询BI报表、多维分析、明细查询单机超高性能查询、宽表聚合集群运维复杂度中中低中高尤其副本和分布式DDL一句话总结如果你需要的是“一个能稳定跑报表、少出幺蛾子的分析型数据库”Doris是很顺手的选择。1.3 我在什么场景下会坚定选DorisDoris官方定位是“面向分析的高性能分布式数据库”我用了半年之后把它适用场景归纳为三类BI报表与看板。MySQL协议对数据部门和后端工程师太友好了任何语言连MySQL的方式都能直接连Doris不用额外写驱动。明细查询与聚合混合负载。既能用主键查单条记录也能跑大范围聚合不需要搭两套系统。需要精确去重和多表join的统计场景。比如UV统计、GMV汇总、漏斗分析Doris在这类场景的稳定性和性能都比Presto更可控。另外值得一提的是Doris的导入生态支持Stream Load、Broker Load、Routine Load、Insert Into等多种方式和Kafka、HDFS、Flink、Spark的集成都比较成熟。对于中小团队来说一套Doris集群可以替代“Presto Hive 一套OLAP库”的组合架构简单很多维护成本也低很多。2. 单机版先跑起来Doris安装部署从下载到建表2.1 下载与版本选择LTS优先别追新我第一次部署时直接选了当时最新的版本结果被一些小问题折腾得够呛。后来学乖了优先选LTS版本或已发布较久的stable版本不建议拿刚发的小版本直接上生产。从Doris官网下载二进制安装包时注意确认操作系统和CPU架构。官方提供x64和ARM的包选错了解压启动后会遇到非法指令这类问题。我用的版本文件类似apache-doris-2.1.x-bin-x64.tar.gz里面已经包含了FE、BE、Broker等组件不需要自己编译。非特殊情况不要自己去从源码编译费时费力不说还容易缺依赖。下载到服务器后解压到统一目录比如/opt/apache-doris/然后分别进到fe和be子目录做配置和启动。2.2 部署前的系统环境准备这几项不做后面全是坑Doris对系统环境的要求不算苛刻但有几项必须提前处理否则启动过程会非常痛苦。JDK版本FE依赖Java运行环境建议JDK 8或JDK 11。BE是C实现不需要Java。文件句柄数BE需要打开大量文件默认的ulimit -n往往不够。建议设置成65535以上顺便把max user processes也调大。swap策略建议关闭或尽量降低swap使用。分析型查询对延迟敏感一旦发生内存换页查询耗时可能瞬间翻倍。时钟同步集群内所有节点要保持时间同步建议部署NTP服务。时间偏移会导致BE心跳异常、元数据判断出错。我部署时的经验是先把这些系统参数写入/etc/security/limits.conf再重启服务器或者至少重启登录会话确保生效。别省这一步否则后面排查“BE状态异常”会花掉几个小时。2.3 启动FE与BE伪分布式跑通只需几分钟单机部署时FE和BE可以放在同一台机器上。虽然生产环境不推荐这样但用于学习、功能验证、给团队做Demo完全够用。启动FEcd /opt/apache-doris/fe ./bin/start_fe.sh --daemonFE默认端口是8030HTTP、9030MySQL协议、9010edit log、9020Thrift RPC。这一步如果用默认端口不用改配置就能直接启动成功。接着用MySQL客户端连接FEmysql -h127.0.0.1 -P9030 -uroot看到Welcome to the MySQL monitor说明FE已经起来了。接下来启动BEcd /opt/apache-doris/be ./bin/start_be.sh --daemonBE启动后不会自动注册到FE需要手动添加一次。在MySQL客户端里执行ALTER SYSTEM ADD BACKEND 127.0.0.1:9050;然后看一下BE状态SHOW PROC /backends;重点看最后一列的Alive字段如果显示true单机版就已经跑通了。提示BE的9050是心跳端口不是数据端口。添加BE时填的IP和端口必须和BE节点自己上报的地址一致否则会报“backend not found”之类的错误。2.4 建表与导入第一份数据先跑通一个完整流程单机版跑起来之后我建议立刻建一张表、导一份数据进去把整个链路走一遍。这一步能帮你快速验证部署是否正常也能让你直观感受到Doris的SQL习惯。建库建表CREATE DATABASE test_db; CREATE TABLE test_db.orders ( order_id BIGINT NOT NULL, user_id BIGINT NOT NULL, city VARCHAR(32), amount DECIMAL(12, 2), status TINYINT, order_time DATETIME ) DUPLICATE KEY(order_id) PARTITION BY RANGE(order_time) () DISTRIBUTED BY HASH(user_id) BUCKETS 12 PROPERTIES ( replication_num 1 );先说明一下这个建表语句里几个关键词的含义DUPLICATE KEY表示明细模型适合保存原始订单数据PARTITION BY RANGE按时间分区方便后续按日期裁剪DISTRIBUTED BY HASH按用户ID分桶确保同一个用户的数据落到同一个分桶里join和聚合时可以减少跨节点数据移动。单机版replication_num设为1即可生产环境通常设为2或3。导入数据使用Stream Load方式这是Doris最常用的本地导入方式curl --location-trusted -u root: \ -H label:test_order_001 \ -H column_separator:, \ -H format:csv_with_names \ -H max_filter_ratio:0.05 \ -T /data/orders.csv \ http://127.0.0.1:8030/api/test_db/orders/_stream_loadlabel是导入事务的唯一标识同一张表里不能重复。max_filter_ratio允许一定比例的错误数据通过避免因为个别脏数据导致整个文件导入失败。2.5 单机环境必须验证的几个点部署完成不等于万事大吉。我每次搭完环境都会做一组“自检清单”大概十几分钟能省掉后面很多排查时间看FE和BE日志。FE日志在fe/log/fe.logBE日志在be/log/be.INFO启动报错基本都会留在这里。执行SHOW PROC /backends确认所有BE都是Alive状态。执行SHOW TABLET FROM test_db.orders查看副本状态正常应该是health为true。跑一条简单查询SELECT city, SUM(amount) FROM test_db.orders GROUP BY city确认向量化执行没有报错。用EXPLAIN SELECT ...看一眼执行计划确认分区裁剪和分桶裁剪生效而不是全表扫描。这套自检流程我后来在每一套集群上线前都会执行一遍比直接跑业务SQL更容易暴露底层问题。3. 上生产前的集群规划FE与BE的角色分工和部署细节3.1 先想清楚要多少台机器很多人部署Doris集群时第一个问题就是“要几台机器”。我给一个比较务实的估算方式。首先要明白FE和BE的定位FE是大脑负责元数据管理、查询解析、生成执行计划BE是肌肉负责数据存储和真正的计算。BE的负载远高于FE所以机器资源要向BE倾斜。我常用的规划思路是数据总量在几十TB以内3台BE起步每台配16核64G或32核128G。FE建议至少3个节点组成高可用组。如果只是开发和测试环境用3台机器每台上面跑一个FE加一个BE勉强能支撑。但生产环境我不建议把FE和BE混部特别是BE负载高的场景会互相影响。磁盘方面BE的数据目录建议使用SSD。Doris的列式存储和点查场景对随机IO有要求SSD和机械盘的查询时延差距非常明显。同时要为BE预留至少20%的空余磁盘否则compaction和导入会撑不住。3.2 FE集群Follower、Observer与元数据一致性FE有两种角色Follower和Observer。Follower参与元数据选举Observer只提供查询服务不参与选举。生产中通常部署1个Follower作为主节点再加2个Follower组成高可用如果读压力大再加Observer扩展。在已启动的Master FE上执行ALTER SYSTEM ADD FOLLOWER fe2_host:9010; ALTER SYSTEM ADD OBSERVER fe3_host:9010;然后在新节点的fe/conf/fe.conf里保证meta_dir配置一致执行启动命令时带上Master的地址cd /opt/apache-doris/fe ./bin/start_fe.sh --helper master_host:9010 --daemon这里有个关键点FE的元数据是极其重要的资产。整个集群的库表结构、分区分桶、副本分布都记录在meta_dir里建议把meta目录放到独立磁盘上并定期备份。我第一次升级集群时因为疏忽FE元数据所在磁盘满掉导致整个集群短暂不可用从那之后我把meta目录的磁盘监控提到了最高优先级。3.3 BE的扩容与副本重新平衡往集群里加BE很简单ALTER SYSTEM ADD BACKEND be2_host:9050;加完之后Doris会自动进行tablet的负载均衡把一部分数据从旧的BE挪到新的BE上。观察进度可以用SHOW PROC /cluster_balance;这个表里能看到tablet在BE之间的移动状态。刚挂上新的BE时你会发现集群性能没有立刻提升反而可能因为数据搬迁占用IO而轻微下降这是正常现象等均衡完成后才会整体变好。我踩过的一个坑是扩容前没有注意磁盘容量差异。BE节点之间磁盘大小不一样时Doris按容量做均衡的效果会打折扣容易出现某个大磁盘的BE还是偏空闲小磁盘的BE已经快满了。所以规划BE机器时尽量保持磁盘规格一致。3.4 端口清单与网络配置的避坑指南多节点部署时网络端口放通是第一步。我以默认配置为例列一下需要放通的端口组件端口用途FE8030FE HTTP服务用于页面和导入FE9030MySQL协议连接端口FE9010FE节点间edit log通信FE9020FE Thrift RPCBE9050BE心跳上报BE9060BE Thrift RPCBE8040BE HTTP服务BE8060BRPC服务具体端口可能随版本微调部署前以官方文档对应版本的参数说明为准。但要注意FE与FE之间、FE与BE之间、BE与BE之间的网络必须全通不能只放通客户端到FE的端口。否则你会遇到“BE状态正常但查询报错”这种非常隐晦的问题。3.5 部署过程中最容易踩到的三个坑我在多次集群部署里踩过的坑大致可以归成三类分享出来希望大家绕开。第一内存参数没有显式设置。BE默认的mem_limit可能高达机器物理内存的90%这个值在生产环境偏大。操作系统需要留内存给page cacheBE和其他进程也需要呼吸空间。我一般显式设置成物理内存的70%-80%再根据负载微调。第二FE和BE混布导致资源争抢。单机测试没问题但生产环境如果BE在跑大查询FE的响应会明显变慢元数据操作都跟着受影响。有条件的话FE用独立机器哪怕配置低一点也没关系。第三BE磁盘写满导致节点自动下线。Doris检测到BE数据目录不可写或剩余空间不足时可能主动把BE标记为不可用。我见过太多因为日志没有清理、数据目录被灌满导致的“集群突然挂掉”事件。上线前务必给BE的数据目录和日志目录配好监控告警。4. 迁移SQL到Doris被Presto惯坏之后我踩过的“missing”坑4.1 先说结论Presto里报“missing”到底是怎么回事“presto doris错误的missing”这个关键词不是第一次出现在我的视野里。用Presto读Doris的场景最常见的报错有两种Column xxx cannot be resolved和Table xxx not found。我和团队排查过多个这样的问题根因基本集中在下面三类。第一类是元数据缓存不一致。Presto通过连接器访问Doris时会把表的schema缓存到连接器侧。如果Doris集群里这张表后续加了列、删了列或改了类型而Presto侧没有刷新缓存就会报“列无法解析”。这和我们凌晨那次故障属于同一类和Doris自身没关系纯粹是联邦查询架构的固有缺陷。第二类是大小写问题。Presto默认会把SQL里未加引号的标识符转成小写而Doris虽然兼容MySQL协议但如果你建库建表时用了大写字母两边对不上就会查不到。解决方案是统一建表规范要么全部小写要么在SQL里用反引号强制大小写。第三类是驱动和字段类型映射问题。老版本的Doris JDBC驱动对部分新数据类型支持不全或者Presto的Doris连接器对DECIMAL、DATETIME这类类型的映射不完整结果表现在查询时就变成“某列不存在”。升级驱动版本通常能解决。我还想强调一个很多人忽略的点Presto里报missing的SQL直接拿到Doris执行往往根本不会报错。因为Doris是自己存数据的查询时能直接看到真实的行列结构。所以这类问题最适合的解法就是把这套报表的查询从Presto迁到Doris来跑而不是在连接器的纠错上绕圈子。4.2 Doris的SQL写法与Presto的差异对照把SQL从Presto迁到Doris语法层面整体平滑但还是有几个需要手工调整的地方。我整理了一份常用对照表功能Presto写法Doris写法时间截断date_trunc(month, ts)date_trunc(ts, month)2.1版本两种皆可字符串聚合array_join(array_agg(x), ,)或string_agggroup_concat(x, ,)模糊匹配LIKE同MySQL支持LIKE近似去重approx_distinct(x)approx_count_distinct(x)精确去重用COUNT(DISTINCT x)JSON数组展开cross join unnest(json_array)LATERAL VIEW explode_json_array(...)列名转义双引号反引号比较常见的坑是date_trunc的参数顺序。Presto习惯把时间单位放前面Doris习惯把时间字段放前面。两种都写错过后来我的做法是统一在Doris里使用DATE_TRUNC(ts, month)这种顺序并在SQL注释里标记清楚。另外Doris对反引号的支持更接近MySQL。如果字段名恰好是保留字比如rank、status、desc记得加反引号否则查询可能直接执行失败。4.3 迁移前必做的三件事把大批SQL从Presto迁到Doris之前我强烈建议先做三件事别急着直接切流。第一用真实的统计SQL跑POC。从业务方拿最近一个月的核心查询SQL在Doris上跑一遍对比行数和指标值。哪怕语法没问题也要确认指标口径一致尤其是去重计数、金额保留位数这些容易产生细微偏差的地方。第二执行计划校验。对每个核心查询用EXPLAIN看执行计划确认关联顺序、分区裁剪、分桶裁剪都符合预期。如果发现某个大表没有走分区裁剪即使查询能跑通性能和稳定性也堪忧。第三压力测试。模拟几个并发用户同时查报表场景观察BE的内存占用和查询耗时的波动。很多迁移后的问题不是单查询跑不动而是并发上来之后内存被打满触发查询失败。4.4 迁移后的性能变化一个报表任务从15分钟到5分钟说一个具体的案例。我们有一张20多亿行的用户行为明细表之前用Presto做UV统计和漏斗分析。Presto需要扫描整张表并跨节点shuffle数据一个复杂的漏斗SQL要跑15分钟左右而且经常遇到资源竞争。迁移到Doris后我把表按事件时间做了分区把需要高频聚合的维度建了物化视图。同样的SQL在Doris里跑只需要5分钟左右如果是命中物化视图的固定指标查询甚至可以压到10秒以内。提速主要来自三方面列式存储减少无效IO、分区裁剪缩小扫描范围、预聚合避免重复计算。当然也要客观说一句Doris不是万能的。如果你的查询模式是超大数据量上的即席探索性分析或者需要经常关联数据湖里的非结构化文件Presto的灵活性仍然有优势。迁移前先想清楚业务的核心诉求是“快”还是“灵活”。5. 运行半年之后我保留下来的Doris调优清单5.1 表模型选错后面全是被动Doris有三种表模型Duplicate、Unique、Aggregate。很多人刚开始建表时不重视结果查询性能差、数据更新逻辑不对回来改表结构成本非常高。我现在的选型逻辑很简单保留明细数据且要原始记录用Duplicate模型。订单流水、日志明细这类。有更新需求比如维表、用户状态、订单状态用Unique模型。2.0之后的版本默认是Merge-on-Write实现查询性能比以前的Merge-on-Read好很多。只关心聚合结果用Aggregate模型。比如每天汇总的计数、求和。举个例子账单流水表我一开始建成了Unique模型以为按订单号更新更安全。后来发现实际上没有更新需求而Unique模型的写入开销比Duplicate大查询也稍慢白白牺牲了性能。改成Duplicate之后同样规模的查询快了不少。5.2 分区分桶设计先按时间分区再按维度分桶分区分桶是Doris调优最值得花时间的地方。我的通用做法是先按时间字段做RANGE分区通常是天或小时再用业务维度做HASH分桶确保同一个用户的记录集中在一个分桶内。分桶数量的设置我是按“每个分桶的数据量控制在几百MB左右”来倒推的。分桶太小会产生大量小文件元数据和调度开销大分桶太大会导致单个桶扫描时间过长并行度不够。一个大概的经验是初期按集群BE数量的2-4倍设置分桶数后续根据实际查询再调整。如果表有持续写入建议开启动态分区避免每天手动加分区PROPERTIES ( dynamic_partition.enable true, dynamic_partition.time_unit DAY, dynamic_partition.start -7, dynamic_partition.end 1, dynamic_partition.buckets 12 )start和end控制保留最近多少天的分区既能满足报表查询又不会让分区数量无限膨胀。5.3 慢查询排错EXPLAIN和Profile的配合使用遇到慢查询我先用EXPLAIN看执行计划判断扫描范围和join策略是否合理。如果处理不了再开启Profile看更细粒度的执行信息SET is_report_success true;执行查询后在FE的HTTP页面或者通过API拉取Profile信息。我重点看三个指标ScanBytes扫描了多少数据。如果很大说明分区裁剪或分桶裁剪没生效。PeakMemory查询峰值内存。如果打满说明join或聚合在某个BE上做了大量shuffle。ExchangeBytes节点间数据传输量。这个值越大查询越慢。常见原因是join键选择不当导致大量数据被shuffle到不同BE。我遇到过最典型的一个问题大表关联维表维表只有几十万行但执行计划里没有用Broadcast Join而是走了Shuffle Join结果每次查询都要在BE之间传一大堆数据。后来在SQL里加上/* BROADCAST */提示耗时直接降了一个数量级。5.4 写入侧Stream Load批量导入和常见报错Doris的导入能力很强但用不好也会让集群难受。Stream Load是我用得最多的导入方式几个实操要点label一定要设计好规则比如源文件日期加批次号。重复的label会直接导入失败这其实是保护机制不是bug。大批量文件建议拆分单个文件超过几GB时拆成多个文件并行导入不要硬灌一个超大的Stream Load任务。设置合理的max_filter_ratio。数据质量没把握时允许1%-5%的错误比例避免整个批次失败。但别调得过大否则脏数据混进去会影响统计结果。常见的导入错误里ETL_RUN_FAIL多半是数据类型转换不匹配比如字符串字段里混入了非数字内容。COMMIT_FAIL则可能是因为BE在提交阶段宕机或网络抖动重试时换一个新label即可。5.5 物化视图在什么时候它真的值得建Doris的物化视图是我最喜欢的特性之一。它本质上是让Doris自动维护一张预聚合的表查询时如果命中物化视图就直接读聚合好的数据不用重新扫明细。我建物化视图的原则是固定的高频聚合查询才会建不确定的探索性查询不要建。比如“按天统计各渠道的收入和订单数”这种写死在报表里的指标就非常适合CREATE MATERIALIZED VIEW mv_channel_daily AS SELECT dt, channel, SUM(amount), COUNT(order_id) FROM orders GROUP BY dt, channel;建完之后不需要手动管Doris会在导入时自动更新。查询时如果SQL能自动匹配到这个物化视图执行计划里会显示读取的是物化视图而不是原始表。需要注意的是物化视图会消耗额外的存储和导入计算资源不要建太多每一张都要有明确的业务目标。5.6 我最后悔没早点知道的三件事最后分享三条经历半年集群运维后最希望第一天就知道的经验。第一compaction参数不要频繁乱调。新用户看到Doris里compaction相关配置容易手痒我一开始也调过结果因为cumulative compaction策略改得不合理导入后数据迟迟没有合并查询变慢。现在我只保留默认策略只在出现大量小文件时介入。第二BE之间的网络质量直接影响查询稳定性。Doris跑高并发查询时BE节点之间会有大量shuffle数据流。如果某个BE的网卡有丢包或延迟抖动查询可能整个失败。生产环境尽量让BE在同一个机架或至少同一个可用区内。第三滚动升级前一定看官方Release Notes。Doris的小版本升级通常可以滚动进行一个个替换BE再更新FE但我遇到过某个中间版本的行为变化没有提前看文档导致升级后SQL执行计划变了。升级前花半小时读Release Notes比升级后排查半天问题有价值得多。我现在这套生产环境的BE已经跑了快一年没有重启FE经历过两次滚动升级元数据没有出过问题。如果你也在Presto和Doris之间纠结我的建议很直接不要看评测文章拿最近的真实SQL和真实数据在Doris上做一次完整的POC行不行它自己会告诉你。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表