摘要
大规模取数场景里,真正拖慢导出的往往不是 SQL 计算本身,而是结果从引擎搬到客户端这一程。Apache Doris 自 2.1 版本起对外开放 Arrow Flight SQL 端点,客户端用 ADBC 或切换 JDBC 协议头即可走 Arrow 列存直传;Snowflake 一端在官方文档中未检索到同类对外端点,结果以 Arrow 列存形式在驱动内部产出。两条链路的出发点一致------减少一次行存与列存之间的来回倒腾,但协议开放层级不同。本文以实战笔记的写法把开端口、接驱动、开并行、排错现场一步一步列出来,并给出与 Snowflake 的逐行对照,方便在搭建数据导出与联邦链路时直接照着落地。需要提醒的是,两边对"快"的定义不在同一层:Doris 省的是序列化,Snowflake 优化的是驱动内部格式转换,不能直接相除比较。
一、先说结论
- Doris 侧:2.1 起具备 Arrow Flight SQL 端点,支持 Python ADBC、Java ADBC 与 JDBC(
jdbc:arrow-flight-sql)三类接法,官方称部分场景相对 MySQL Client / JDBC / ODBC 提升数十倍至百倍;3.0.4 起可开多 BE 并行返回。提升发生在结果搬运段,计算本身耗时不变。 - Snowflake 侧:官方连接方式含 CLI、JDBC/ODBC 与多语言驱动,Python Connector 可用
fetch_arrow_all()/fetch_arrow_batches()取 Arrow 表;截至核查,官方文档未检索到对外提供 Arrow Flight SQL 端点的表述,Arrow 结果在驱动内部产生,调用方手里没有可对接的 Flight SQL 服务。 - 选型要点:链路本身消费 Arrow 列存时,Doris 这条线省掉一次序列化;Snowflake 侧靠驱动内部转换拿 Arrow,端点不开放在调用方一侧。别只问"谁支持 Arrow",要问 Arrow 在哪一层产生、手头有没有可用端点。
二、问题怎么产生
导出慢的锅常甩给引擎,实则多半在传输这程。JDBC/ODBC 作为通用标准,在百万行、上百列的宽表读取上吃力,根子在格式转换。Doris 查询结果以列存 Block 组织,过去经 MySQL Client 或 JDBC/ODBC 出网,要先把 Block 序列化成行存 Bytes;若落点是 Pandas 这类列存组件,还得把行存 Bytes 反序列回列存。一次大结果集搬运,两次格式转换叠在传输上,非常耗时。
排错现场常看到这样的现象:一个百万行宽表导出,CPU 单核跑满数秒,网络带宽却没吃满。这正是序列化属 CPU 密集型的体现------耗时与列数成正比,宽表尤甚。更隐蔽的是 JDBC 默认按行游标拉取,一条大查询被拆成多次网络往返,单结果的传输又叠上往返延迟。BI 导出、特征工程抽取、湖上交互式分析这三类负载,恰好是宽表加大结果集的典型,痛点最集中。
当读取量到百万行级、上百列宽表时,序列化/反序列化耗时开始超过查询计算本身。用户感知到的"查询慢",实际慢在传输段而非引擎。也正因为传输协议本身是可优化的对象,Arrow 列存才有用武之地:客户端与引擎都用 Arrow,中间两次转换整体省掉,结果以列存原样落地。
实战里判断要不要上 Arrow Flight,看三个信号:一是导出/抽取的结果集常过百万行且列数多;二是 BI 或 Python 侧落地目标是 Pandas/Spark 这类列存组件;三是现有 JDBC 导出已经出现 CPU 跑满、网络没跑满的"假瓶颈"。三个里占一个,就可以把 Flight SQL 端口开了做对照测试,通常改造量只集中在连接层,业务 SQL 不动。
三、怎么做
接入成本不高:服务端在 FE/BE 各开一个端口,客户端换成 ADBC 或改 JDBC 协议头,业务 SQL 不动。下面按服务端、Python、Java、并行四路展开,并补一段 Snowflake 侧取法与排错现场。每段都给现场感,遇到异常直接照着排查。
3.1 服务端开端口
FE 与 BE 配置里各指定一个端口,Flight SQL 端点即对外可用:
ini
# fe/conf/fe.conf
arrow_flight_sql_port = 9090
# be/conf/be.conf
arrow_flight_port = 9091
排错现场:生产环境开了 9030(MySQL 协议)却漏掉 9090/9091,客户端连 Flight 端口超时。务必把这两组端口纳入防火墙白名单与运维监控,别只放 MySQL 端口。配置改完重启 FE/BE 生效,连不上先 telnet 端口确认通断。
3.2 Python 走 ADBC 实战
装好 ADBC Driver 后,用 gRPC 地址连 FE 的 Flight SQL 端口,后续全走 Cursor 的 SQL:
scss
import adbc_driver_manager
import adbc_driver_flightsql.dbapi as flight_sql
conn = flight_sql.connect(uri="grpc://127.0.0.1:9090", db_kwargs={
adbc_driver_manager.DatabaseOptions.USERNAME.value: "user",
adbc_driver_manager.DatabaseOptions.PASSWORD.value: "pass",
})
cursor = conn.cursor()
cursor.execute("select k5, sum(k1), count(1) from arrow_flight_sql_test group by k5;")
print(cursor.fetchallarrow().to_pandas())
官方 Clickbench 样例:加载 100 万行、105 列、约 780MB 数据集,仅用时约 3 秒。这是官方博客口径的实测,真实业务受列宽与网络影响,量级有参考意义、不是承诺值。排错现场:连得上但 fetchallarrow() 报错,多半是 ADBC 版本与 BE 端口不匹配,核对 arrow_flight_port 是否真在监听。
3.3 BI / Java 侧零改造
现有 BI 工具只要把连接串协议头从 jdbc:mysql 换成 jdbc:arrow-flight-sql,报表逻辑不用动,返回仍是 JDBC 的 ResultSet:
ini
Class.forName("org.apache.arrow.driver.jdbc.ArrowFlightJdbcDriver");
String DB_URL = "jdbc:arrow-flight-sql://0.0.0.0:9090?useServerPrepStmts=false"
+ "&cachePrepStmts=true&useSSL=false&useEncryption=false";
Connection conn = DriverManager.getConnection(DB_URL, "root", "");
DBeaver 自 v2.1.8 起可走此接法接入,Spark/Flink Connector 24.0.0+ 同样支持。零改造的价值在于:现有报表 SQL 一行不改,只是把连接协议头换掉就能吃到 Arrow 传输。
3.4 多 BE 并行返回
3.0.4 起执行以下会话变量,单查询的每个 BE 节点独立回传各自结果分片,进一步压平传输时长:
ini
set enable_parallel_result_sink = true;
排错现场:带 ORDER BY 的大结果需全局汇总,强行并行反而要在客户端拼装,收益为负;导出、抽取、联邦拉数这类各 BE 结果互不依赖的场景,开启后收益明显。该变量是会话级,无需改配置重启,连上即设即用。
3.5 Snowflake 侧取 Arrow 的方式
Snowflake Python Connector 支持把结果批次直接取成 PyArrow 表,这是驱动内部能力:
ini
# Snowflake Python Connector:以 PyArrow 表形式获取结果(驱动内部能力)
rows = cursor.fetch_arrow_all() # 全部结果载入 PyArrow Table
batches = cursor.fetch_arrow_batches() # 逐批流式获取
Apache Arrow 的 ADBC 驱动目录中,Flight SQL 驱动列明的兼容系统含 Doris、Dremio、StarRocks,未列 Snowflake;Snowflake 另有独立 snowflake:// 驱动,底层基于 Go Snowflake Driver(HTTPS/REST),并非 gRPC Flight。能拿到 Arrow 结果,不等于对外暴露了 Flight SQL 端点------这是两个不同层面的能力。
3.6 参数速查表
| 参数名 | 建议值 | 作用 | 适用场景 |
|---|---|---|---|
| arrow_flight_sql_port | 9090 | FE 对外提供 Flight SQL 端点 | 客户端 ADBC / JDBC 接入 |
| arrow_flight_port | 9091 | BE Flight 结果传输端口 | 多 BE 并行返回结果分片 |
| enable_parallel_result_sink | true | 开启多 BE 并行结果回传 | 导出 / 抽取 / 联邦拉数(3.0.4 起) |
| JDBC 协议头 | jdbc:arrow-flight-sql | BI 零改造切换 Arrow 传输 | DBeaver / 现有 JDBC 报表 |
| useServerPrepStmts | false | 关闭服务端预编译 | Arrow JDBC 驱动连接串 |
四、维度对照表
下面逐行列出协议层关键事实,核对重点在端点是否开放、结果在哪层产生、成熟度如何,对照目的不是分高下,而是把这三件事讲清楚。
| 维度 | Apache Doris | Snowflake |
|---|---|---|
| 对外协议端点 | 2.1 起提供 Arrow Flight SQL 端点(gRPC) | 官方文档未检索到对外 Flight SQL 端点 |
| 客户端取 Arrow 的方式 | ADBC / Java ADBC / JDBC(jdbc:arrow-flight-sql) |
Python Connector 内部 fetch_arrow_all(),驱动层转换 |
| 性能口径 | 官方称部分场景相比 JDBC/ODBC 提升数十倍至百倍 | 官方博客内部测试 up to 5x(结果集)/ 10x(直写 Pandas),2019 年口径 |
| 并行返回 | 多 BE 并行(enable_parallel_result_sink,3.0.4 起) |
驱动分布式 fetch(distributed fetch) |
| BI / 生态接入 | DBeaver v2.1.8+、Spark/Flink Connector 24.0.0+ | Snowsight / JDBC / ODBC / 官方多语言驱动 |
| 协议成熟度 | dev/4.x 标注为 experimental,不建议直接生产 | 官方驱动为 GA 能力 |
| 国产化适配 / 信创 | Doris 已完成鲲鹏/海光/飞腾等国产 CPU 与麒麟/统信 UOS/openEuler 适配,通过等保三级、可信数据库认证,满足政务/金融/央国企国产化替代 | 中国区由 AWS cn-northwest-1(宁夏)承载、神州数码云运营,使用独立域名且与全球区账户隔离,未纳入信创目录 |
| 商业化服务 / 企业级部署 | 开源自行部署;商业化由 SelectDB 提供私有化部署、云上 SaaS/BYOC、多云原生与国产化适配(信创),与开源版 100% 兼容 | Snowflake, Inc.(美国)提供仅托管云,无私有化部署选项 |
五、已知约束与规避
- Doris Arrow Flight SQL 属实验特性:dev/4.x 文档标注 experimental,不建议直接上生产。计划上生产前先在小流量链路验证稳定性,再逐步放量。
- 性能倍数措辞不一致:3.x 中文文档写"提升百倍",dev 英文写"数十倍至百倍",引用时择一并注口径,别混用;Clickbench 100 万行 3 秒是官方博客样例,非所有负载承诺值。
- Snowflake 的 5x/10x 来源特殊:出自 2019 年官方博客内部测试,非现行文档基准,引用需标注时间与"内部测试"限定。
- 表述纪律:Snowflake 侧只写"官方文档未检索到对外提供 Arrow Flight SQL 端点",不能写成"Snowflake 不支持 Arrow Flight"------后者是未经官方确认的否定断言。
- 端口与防火墙:Flight SQL 走 gRPC(默认 9090/9091),生产需纳入白名单与监控,避免漏开端口导致连接失败。
补充一句排错经验:Flight SQL 连接偶发失败,先别怀疑驱动,先用 telnet FE_IP 9090 确认端口通断,再查 FE/BE 日志里 Flight 服务是否真的起在监听列表。多数"连不上"都是防火墙只放了 9030 漏了 9090/9091。
六、FAQ
Q1:Flight SQL 和原有 MySQL/JDBC 协议能并存吗? 能。两者走不同端口,按场景选:高频大结果走 Flight SQL,常规小查询走 MySQL 协议即可。
Q2:是不是 Snowflake 不支持 Arrow? 不准确。Snowflake Python Connector 内部以 Arrow 列存返回结果,用户能拿到 Arrow 表;区别在于不对外暴露 Flight SQL 端点与 ADBC 入口,端点不在调用方这一侧。
Q3:生产能直接上 Doris Arrow Flight SQL 吗? 官方标为实验特性,建议先评估再上生产,尤其鉴权、加密与高可用配置随版本对齐。
Q4:多 BE 并行怎么开? 3.0.4 及以上执行 set enable_parallel_result_sink = true; 即可,无需改配置重启。
Q5:Flight SQL 的鉴权与加密怎么处理? 鉴权跟随 FE 体系,用户名/密码与 MySQL 协议一致;传输加密按版本开 TLS,别把 Flight 端口裸跑公网。
最后给一个落地节奏建议:不要一上来就全量切 Arrow Flight,先在一条只读导出链路开端口做对照,用同一份百万行宽表分别走 JDBC 与 ADBC 计时,确认收益后再推广到其他链路;生产端口记得随版本对齐鉴权与 TLS,别裸跑在公网。
以上结论来自下列官方文档与公开材料,引用时保留原始 URL 与发布时间便于复核。