新闻详情

新闻详情

首页 / 资讯中心 / 详情

Presto Native Execution Thrift 序列化层全解析:从 JSON 到 Thrift 的过渡架构与代码生成管线

发布时间:2026/9/24 23:38:08来源:尧图网络
Presto Native Execution Thrift 序列化层全解析:从 JSON 到 Thrift 的过渡架构与代码生成管线
大数据数据库后端【免费下载链接】prestoThe official home of the Presto distributed SQL query engine for big data项目地址https://gitcode.com/gh_mirrors/pre/presto点击查看免费下载导读本文围绕 Presto 原生执行引擎presto-native-execution / presto_cpp中与 Coordinator 通信所用的 Thrift 序列化层展开完整讲解其设计动机、双层代码生成管线、toThrift/fromThrift转换机制以及构建与测试方式。读完本文你将理解 presto_cpp 如何从 JSON 协议平滑过渡到 fbthrift 协议掌握presto_thrift.thrift→ProtocolToThrift.[h|cpp]的完整生成链路并能在此基础上自行扩展新的 Thrift 结构。背景presto_cpp 为什么需要一套 Thrift 序列化层Presto 是一个分布式 SQL 查询引擎Coordinator 负责查询规划与调度Worker 负责执行。presto-native-execution即 presto_cpp是用 C 实现的原生执行引擎它与 Presto Coordinator 之间需要频繁交换任务状态TaskStatus、任务信息TaskInfo等数据。presto-native-execution/presto_cpp/main/thrift/README.md 开宗明义地指出这个目录承载的正是与 Presto Coordinator 通信所使用的 Thrift 序列化serde。历史上 presto_cpp 与 Coordinator 的通信采用 JSON 序列化presto_protocol 中定义了与 Java 端一致的 JSON 协议结构。随着演进项目决定转向更紧凑、高性能的 Thrift 二进制协议但迁移并非一蹴而就而是处于JSON 与 Thrift 并存的过渡期。因此 README 明确描述了最终状态与过渡期状态最终状态只保留presto_thrift.thrift文件及其 fbthrift 生成的代码过渡期状态需要维护两套内部数据结构JSON 派生结构与 Thrift 派生结构之间的转换代码。换句话说这个目录的核心使命是在过渡期内把 JSON 派生的内部对象转换成对应的 Thrift struct供 Thrift 协议端点使用。从源码结构看这个目标已经基本实现当前 thrift 目录下同时存在 IDL 定义presto_thrift.thrift、presto_native.thrift、代码生成脚本thrift2json.py、presto_protocol-to-thrift-json.py、mustache 模板ProtocolToThrift-cpp.mustache、ProtocolToThrift-hpp.mustache、生成产物ProtocolToThrift.h、ProtocolToThrift.cpp以及通用读写封装ThriftIO.h并配有独立的单元测试tests/ThriftIOTest.cpp。目录结构与核心文件一览先列出该模块的关键文件及其职责方便后续对照阅读文件职责presto_thrift.thrift与 Presto Java 协议对应的 Thrift IDL 定义任务、算子、会话等结构presto_native.thriftpresto_cpp 原生扩展的 Thrift IDLthrift2json.py将 thrift IDL 解析为 JSON 描述presto_thrift.jsonpresto_protocol-to-thrift-json.py将 thrift JSON 描述与 presto_protocol JSON 合并生成转换映射presto_protocol-to-thrift-json.yml上述脚本的配置字段映射、跳过列表、wrapper/connector/special 分类ProtocolToThrift-cpp.mustache / ProtocolToThrift-hpp.mustachechevron 模板产出转换代码ProtocolToThrift.h / ProtocolToThrift.cpp生成的toThrift/fromThrift转换实现ThriftIO.h基于 BinaryProtocol 的通用读写封装thriftRead/thriftWriteMakefile / CMakeLists.txt生成与构建入口special/需要手写特殊转换逻辑的结构如TaskId、ConnectorSplit、OperatorInfoUnion等tests/ThriftIOTest.cpp序列化往返一致性测试双层代码生成管线从 .thrift 到 ProtocolToThriftREADME 给出了完整的代码生成流程图这是理解整个模块的钥匙。将其整理为更清晰的文字版presto_thrift.thrift ──→ fbthrift ──→ $BUILDDIR/presto_cpp/main/thrift/ProtocolToThrift.[h|cpp] │ ▼ thrift2json.py │ ▼ presto_thrift.json presto_protocol/presto_protocol.json presto_protocol-to-thrift-json.yml │ │ │ │ ▼ │ └──────────────→ presto_protocol-to-thrift-json.py ←─────────────┘ │ ▼ presto_protocol-to-thrift-json.json │ │ ProtocolToThrift-cpp.mustache │ │ ProtocolToThrift-hpp.mustache │ │ │ │ ▼ │ ▼ ▼ chevron ←──────────────┘ chevron ←─────────────┘ │ │ ▼ ▼ ProtocolToThrift.cpp ProtocolToThrift.h整条链路可以拆成两大部分下面分别展开。第一步thrift2json.py —— 把 Thrift IDL 转成 JSON 描述thrift2json.py 的作用是使用ptsd_jbrollptsd Thrift 解析器的一个 fork把presto_thrift.thrift解析成 JSON 表示。脚本的核心逻辑值得注意预处理preprocessIDL 中由 drift 生成的注释drift.recursive_referencetrue在 C 侧会报错因此先用正则将其剔除同时去掉行尾的()生成临时文件temp_presto_thrift.thrift解析完再删除类型映射typeMap/str_type把 Thrift 基础类型映射为 C 类型例如i16 → int16_t、i32 → int32_t、i64 → int64_t容器类型映射为std::map...、std::list...、std::set...结构提取enum/struct/items遍历 AST把enum提取为{enum, class_name, elements}把struct/union提取为{class_name, fields[...], struct|union}每个字段记录field_name、field_type、optional/required与tag输出以// This file is generated DO NOT EDIT generated注释开头打印完整的 JSON。命令级用法对应 Makefile 中的规则./thrift2json.py presto_thrift.thrift | jq . presto_thrift.json第二步presto_protocol-to-thrift-json.py —— 合并两份协议描述presto_protocol-to-thrift-json.py 的输入有两个presto_thrift.json上一步从 Thrift IDL 得到的 JSONpresto_protocol.json实际构建中使用../../presto_protocol/core/presto_protocol_core.jsonpresto_protocol 代码生成器产出的、与 Java 端一致的 JSON 协议描述。脚本将它们合并为presto_protocol-to-thrift-json.json这个合并文件描述了从 JSON 内部结构到 Thrift 结构的转换。其关键处理逻辑包括字段级转换标记verify()计算 Thrift 字段集合与 protocol 字段集合的交集落在交集内的字段会被标记convert true其余字段会向 stderr 打印Missing protocol fields/Missing thrift fields告警字段名映射process_fields()依据 YAML 配置中的fields映射为字段挂上proto_name即 protocol 侧的字段名分类处理SkipStruct跳过 presto_cpp 中不使用的结构如ExchangeClientStatus、StageId等共 14 个StructInProtocolCore标记定义在presto_protocol_core.h中的结构WrapperStruct单字段包装结构如ConnectorId、PlanNodeId、TransactionId、HostAddress等直接展开其唯一字段ConnectorStruct连接器相关结构如ConnectorSplit、ConnectorTableHandle等Special需要手写特殊实现的 8 个结构ConnectorTransactionHandle、ConnectorSplit、QualifiedObjectName、OperatorInfoUnion、OutputBufferId、TaskId、TypeSignature其实现位于special/*.incunion结构如OperatorInfoUnion、ExecutionWriterTargetUnion通过removesuffix(Union)推断 protocol 侧名称并按StructMap配置覆盖字段类型。第三步chevron 模板渲染生成 C 代码presto_protocol-to-thrift-json.json最终交给 chevronMustache 模板引擎渲染两个模板产出实际的 C 代码# Makefile 中的生成规则 ./presto_protocol-to-thrift-json.py presto_thrift.json ../../presto_protocol/core/presto_protocol_core.json | jq . presto_protocol-to-thrift-json.json echo // DO NOT EDIT : This file is generated by presto_protocol-to-thrift-json.py ProtocolToThrift.h chevron -d presto_protocol-to-thrift-json.json ProtocolToThrift-hpp.mustache ProtocolToThrift.h clang-format -stylefile -i ProtocolToThrift.h # ProtocolToThrift.cpp 同理使用 ProtocolToThrift-cpp.mustache模板会为每种结构生成对应的toThriftJSON 结构 → Thrift 结构与fromThriftThrift 结构 → JSON 结构函数声明/定义。从生成的 ProtocolToThrift.cpp 首行// DO NOT EDIT : This file is generated by presto_protocol-to-thrift-json.py可以看出它是构建期产物开发者不应手工修改。转换语义toThrift 与 fromThriftREADME 指出代码生成会为每一个同时存在于 JSON 协议中的 Thrift 结构生成toThrift函数。当前唯一被 Thrift 协议端点真正使用的根类是TaskStatus用于返回.getTaskStatus端点的结果为此需要把 JSON 派生的TaskStatus转成对应的 Thrift struct。基础类型的转换ProtocolToThrift-cpp.mustache 开头定义了基础类型转换注释明确说明这些本可以用更通用的模板覆盖但这样做可以保证只生成到受支持的 Thrift 数据类型的转换void toThrift(const std::string proto, std::string thrift) { thrift proto; } void toThrift(const bool proto, bool thrift) { thrift proto; } void toThrift(const int16_t proto, int16_t thrift) { thrift proto; } void toThrift(const int32_t proto, int32_t thrift) { thrift proto; } void toThrift(const int64_t proto, int64_t thrift) { thrift proto; } void toThrift(const double proto, double thrift) { thrift proto; }两个特殊映射值得一提Duration与DataSize这类带单位的数值在 Thrift 侧统一以纯数值表示void toThrift(const facebook::presto::protocol::Duration duration, double thrift) { thrift duration.getValue(facebook::presto::protocol::TimeUnit::MILLISECONDS); } void toThrift(const facebook::presto::protocol::DataSize dataSize, double thrift) { thrift dataSize.getValue(facebook::presto::protocol::DataUnit::BYTE); }即时长统一换算为毫秒数据大小统一换算为字节fromThrift方向则反向包装回Duration/DataSize。这保证了跨协议传输时单位语义不失真。容器与指针的泛型转换模板还生成了一系列泛型转换覆盖std::shared_ptr、std::vector、std::set、std::map以及 Thrift 的optional_field_ref例如template typename P, typename T void toThrift(const std::shared_ptrP proto, std::shared_ptrT thrift) { if (proto) { thrift std::make_sharedT(); toThrift(*proto, *thrift); } } template typename V, typename S void toThrift(const std::vectorV v, std::setS s) { S toItem; for (const auto fromItem : v) { toThrift(fromItem, toItem); s.insert(std::move(toItem)); } }值得关注的是std::vector → std::set的转换JSON 侧为 list、Thrift 侧为 set例如TaskStatus.completedDriverGroups和blockedReasons它逐元素转换并去重。toThrift/fromThrift是对称成对设计的模板中两类函数均覆盖了相同的数据形状。struct / enum / union / wrapper 的分支模板对于每种 Thrift 结构模板按类型展开不同的代码struct逐字段调用toThrift(proto.proto_name, thrift.field_name_ref())可选字段optional走optional_field_ref路径enum直接按底层 int 值强转保证两套枚举数值一致void toThrift(const facebook::presto::protocol::Type proto, Type thrift) { thrift (Type)(static_castint(proto)); }union如OperatorInfoUniontoThrift用std::dynamic_pointer_cast判断 protocol 侧具体子类型并调用set_field_namefromThrift用thrift.getType() Union::Type::field_name反向分派wrapper如ConnectorId、PlanNodeId只展开唯一字段connector如ConnectorSplitfromThrift优先用connectorId customSerializedValue走连接器协议反序列化getConnectorProtocol(...).deserialize(...)否则退回jsonValue的 JSON 解析special引入special/*.inc的手写实现。例如 TaskId.cpp.inc 把 JSON 侧形如queryId.stageId.taskId.attempt的字符串 TaskId 按.拆分为 5 段映射到嵌套的StageExecutionId → StageId结构ConnectorSplit.cpp.inc 则额外处理了connectorId $remote的远程 Split 场景将自定义序列化值作为RemoteSplit的 Thrift 负载读取后再转回 protocol 结构。ThriftIO.h二进制协议读写封装转换出的 Thrift 结构最终要落到线缆上。ThriftIO.h 基于 fbthrift 的 BinaryProtocol 提供两个通用函数template typename T void thriftRead(const std::string data, std::shared_ptrT buffer) { auto inBuf folly::IOBuf::wrapBuffer(data.data(), data.size()); apache::thrift::BinaryProtocolReader reader; reader.setInput(inBuf.get()); buffer-read(reader); } template typename T std::unique_ptrfolly::IOBuf thriftWriteIOBuf(T data) { folly::IOBufQueue outQueue; apache::thrift::BinaryProtocolWriter writer; writer.setOutput(outQueue); data.write(writer); return outQueue.move(); } template typename T std::string thriftWrite(T data) { return thriftWriteIOBuf(data)-moveToFbString().toStdString(); }即thriftWrite用 BinaryProtocolWriter 序列化为std::stringthriftRead用 BinaryProtocolReader 反序列化。这套封装让上层只需关心类型无需接触 IOBuf/队列细节。构建集成CMake 与 fbthrift 代码生成CMakeLists.txt 展示了该模块如何接入 presto_cpp 的构建通过find_program(THRIFT1 thrift1)与find_path(THRIFT_INCLUDES ...)定位 fbthrift 工具链include(ThriftLibrary.cmake)后调用两次thrift_library(...)presto_thrift由presto_thrift.thrift生成PrestoThrift服务与类型cpp2presto_native由presto_native.thrift生成原生扩展类型两者都依赖FBThrift::thriftcpp2与 Folly手工转换代码编译为静态库presto_thrift_extra包含ProtocolToThrift.cpp并声明对presto_thrift-cpp2的构建依赖仅当PRESTO_ENABLE_TESTING开启时才add_subdirectory(tests)编译测试。README 中流程图顶部的$BUILDDIR/presto_cpp/main/thrift/ProtocolToThrift.[h|cpp]正对应 CMake 里${CMAKE_CURRENT_BINARY_DIR}/presto_cpp/main/thrift的输出目录。端到端调用链/v1/task/{taskId}/status 如何返回 ThriftREADME 提到当前只有一个 Thrift 根类TaskStatus被用于返回.getTaskStatus端点结果。在 TaskResource.cpp 中可以验证这条真实调用链getTaskStatus()处理GET /v1/task/{taskId}/status读取 HTTP 头中的X-Presto-Current-StategetCurrentState与X-Presto-Max-WaitgetMaxWaitshouldUseThrift(message)检查请求的Accept头是否包含 Thrift MIME 类型http::kMimeTypeApplicationThrift从而决定响应走 Thrift 还是 JSON —— 这正是过渡期双协议并存在 HTTP 层的体现通过sendPrestoResponseprotocol::TaskStatus, thrift::TaskStatus(...)发送响应其实现为template typename T, typename ThriftT void sendPrestoResponse( proxygen::ResponseHandler* downstream, const T data, bool sendThrift) { if (sendThrift) { ThriftT thriftData; toThrift(data, thriftData); http::sendOkThriftResponse(downstream, thriftWrite(thriftData)); } else { http::sendOkResponse(downstream, json(data)); } }即先调用生成的toThrift把 JSON 派生的protocol::TaskStatus转为thrift::TaskStatus再用thriftWrite序列化为二进制并作为 Thrift 响应返回。getTaskInfo端点同样以sendPrestoResponseprotocol::TaskInfo, thrift::TaskInfo的方式支持双协议。也就是说虽然 README 写于迁移早期只有TaskStatus一个根类当前仓库中TaskInfo等结构也已接入同一套转换机制。测试验证ThriftIO 往返一致性tests/ThriftIOTest.cpp 使用 GoogleTest 对序列化层做验证。测试基类ThriftIOTest提供testThriftRoundTrips覆盖三条断言thriftWrite→thriftRead往返后对象相等thriftWriteIOBuf→thriftRead往返后对象相等两种序列化方式产出的字节串完全一致。具体用例覆盖了各种边界条件空字符串、大数据量1000 字符字符串 INT32_MAX、负数、零值、嵌套结构TaskId内含StageExecutionId→StageId两层嵌套以及BroadcastFileFooter的空/单/多/大/含零负值等多种 pageSizes。此外 TaskStatusTest.cpp 等测试也直接调用thrift::toThrift验证转换函数行为这些测试由 tests/CMakeLists.txt 接入构建。如何扩展新增一个 Thrift 结构的一般步骤基于上述代码生成管线向该模块新增结构的一般路径可以归纳为在presto_thrift.thrift中定义或扩展 struct/enum遵循已有的字段命名与编号风格如TaskStatus从 1 开始连续编号按需更新presto_protocol-to-thrift-json.yml配置字段名不一致时加入StructMap.fields例如TaskStatus.selfUri ↔ self、Lifespan.grouped ↔ isgroup若结构在 presto_cpp 中不使用加入SkipStruct若是单字段包装结构加入WrapperStruct若是连接器结构加入ConnectorStruct若需要手写转换加入Special并在 special/ 下提供xxx.cpp.inc/xxx.hpp.inc重新运行 Makefile 目标make presto_protocol-to-thrift-json.json与make ProtocolToThrift.h ProtocolToThrift.cpp或用 CMake 触发 thrift 代码生成与presto_thrift_extra编译在 tests/ThriftIOTest.cpp 中补充往返测试用例遵循testThriftRoundTrips模式。小结presto-native-execution 的 thrift 目录是JSON 协议向 Thrift 协议迁移的过渡性基础设施它以presto_thrift.thrift为单一事实来源通过thrift2json.py与presto_protocol-to-thrift-json.py两段脚本将 Thrift IDL 与 presto_protocol 的 JSON 协议合并为转换映射再经 chevron mustache 模板批量产出toThrift/fromThrift转换代码配合ThriftIO.h的 BinaryProtocol 读写封装最终在TaskResource的 HTTP 端点中按Accept头动态选择 Thrift 或 JSON 响应。理解这条管线不仅能看到 presto_cpp 与 Coordinator 通信协议的演进路径也为后续扩展新的 Thrift 结构提供了清晰的落点。赞分享大数据数据库后端【免费下载链接】prestoThe official home of the Presto distributed SQL query engine for big data项目地址https://gitcode.com/gh_mirrors/pre/presto点击查看免费下载相关推荐dromara/disjob的序列化对比JSON/Protobuf/Thriftdromara/disjob的序列化对比JSON/Protobuf/Thrift 引言 在分布式任务调度框架dromara/disjob中序列化SeriaPresto Thrift Connector 完全指南通过 Thrift 协议集成任意外部存储系统Presto Thrift Connector 完全指南通过 Thrift 协议集成任意外部存储系统 导读 本文全面讲解 Presto 中 Thrift Co大数据数据库后端Apache Thrift Delphi 库使用指南版本要求、分层架构与序列化实战Apache Thrift Delphi 库使用指南版本要求、分层架构与序列化实战 Apache Thrift 的 Delphi 软件库 lib/delph后端RPC框架序列化代码生成上一篇终极GitHub加速指南如何让国内访问速度提升10倍的简单方案下一篇告别网盘下载困境这款开源工具如何让九大网盘下载体验焕然一新创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

汽车电子底层软件开发:AUTOSAR与CAN总线实战解析 2026/9/24 23:59:54

汽车电子底层软件开发:AUTOSAR与CAN总线实战解析

1. 这门“汽车电子底层软件开发就业课”到底在教什么?——不是写个LED闪烁就能上岗的很多人看到“汽车电子底层软件开发就业课”这个标题,第一反应是:不就是嵌入式C语言单片机CAN通信?刷几道LeetCode、调通一个STM32 CAN收发例程&…

阅读更多 →
Vim基础操作全攻略:保存退出、模式切换与高频命令实战 2026/9/24 23:59:54

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

阅读更多 →
Python+CNN车牌识别实战:从数据预处理到模型训练与部署 2026/9/24 23:59:54

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

阅读更多 →
AI元人文:从工具使用到思维重构的深度探索 2026/9/24 23:59:54

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

阅读更多 →
《AI Agent 场景应用 - MobileOpenClaw》第5-9节:会话上下文细化处理实战指南 2026/9/24 23:59:47

《AI Agent 场景应用 - MobileOpenClaw》第5-9节:会话上下文细化处理实战指南

文档教程后端 【免费下载链接】CodeGuide :books: 本代码库是作者小傅哥多年从事一线互联网 Java 开发的学习历程技术汇总,旨在为大家提供一个清晰详细的学习教程,侧重点更倾向编写Java核心内容。如果本仓库能为您提供帮助,请给予支持(关注、…

阅读更多 →
写出来的,和没写的——七个模块,一副骨头 2026/9/24 23:59:47

写出来的,和没写的——七个模块,一副骨头

「合金日记」第 85 篇 「小艾说」第 34 期 幕后弧(换弧开篇) 从「写谁」转向「怎么写」 专栏连载中 前篇:《听漏了,还是听深了——一个 a,一句禅》 模块 骨架 沉默 对位 骨头 没看过前篇也能读 没看过前八十…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞