第一次接触 Apache Wayang 是在一次交流会上,当时有个问题让我印象很深:“如果业务代码里全是 Spark API,跑了一年之后发现 Flink 在某些场景更省资源,你打算花多久把代码改过去?”台下没人敢接话。这正是当下开源数据处理生态最微妙的痛点——引擎不稀缺,稀缺的是“不被引擎绑架”的自由。Apache Wayang 这个项目,给我的第一印象就是它在正面回应这件事:与其再造一个更强的执行引擎,不如做一层引擎指挥层,让同一套业务代码可以在 Spark、Flink、PostgreSQL、本地 Java 流等不同平台间自动选择、甚至可以拆开分配到多个引擎上同时执行。这篇文章我会从设计思路、内部执行链路、实际跑通的代码,以及我在真实任务里踩过的坑,完整聊聊它到底值不值得用。
1. 开源数据处理生态越繁荣,选型反而越纠结
1.1 每个框架都在某一环很强,却很难通吃
最近经常看到有人在搜“王者荣耀实时数据处理怎么做到的”这类问题,背后的潜台词是:最好有个足够强的引擎,把高吞吐流式计算、离线批处理、即席查询、机器学习训练全包了。但现实是,开源数据处理框架各自占据一个山头:Spark 在批处理和统一分析上生态最全,Flink 在流式数据处理上有口皆碑,Trino/Presto 擅长联邦查询和交互式 SQL,ClickHouse 扛得住高并发聚合,PostgreSQL 在关系型数据建模上依然能打。
这些框架没有一个能在所有场景下都做到最优。更麻烦的是,它们之间的 API 互不兼容。今天你用 Spark 的 DataFrame 写了一套清洗逻辑,明天想换到 Flink SQL,表面上是改方言,实际上依赖、调优参数、UDF 注册方式全都要推倒重来。我在团队里见过太多类似的项目:初期技术选型时大家拍脑袋选了一个框架,半年后业务阶段变化,发现当初的选择成了负担,可这个时候代码已经长成了“代码屎山”,重构的代价比迁移本身还高。
1.2 真正的瓶颈不是引擎能力,而是“绑定”
如果把数据处理任务比作出行,Spark 是轿车,Flink 是地铁,PostgreSQL 是公交车专用道。每个工具都有优势路段,但如果你从出发那一刻就选定“只坐轿车”,遇到拥堵、限行、维修路段也只能硬扛。现实里更合理的做法是分段规划:这段路坐地铁、那段路打车、最后几百米步行。
Apache Wayang 想做的,就是那个智能出行规划器。它不参与具体的运输,只负责帮你判断哪一段路用哪个交通工具更划算,并在规划完成后调度对应的交通工具执行。放到数据处理语境下,它做的是“引擎中立化”——你把业务逻辑用 Wayang 的接口写一遍,它负责在运行时决定:这个 filter 是丢给 Spark 还是本地流处理,这个 join 是下推到 PostgreSQL 还是跑在 Flink 上。
这听起来像中间层,但和传统中间层有个本质区别:它不是做统一的“减法”,而是做动态的“组合”。同一个任务可以被拆成多个子任务,交给不同引擎并行执行。这才是它真正让我觉得有价值的地方。
1.3 为什么现有的“统一”方案总觉得差一口气
有人可能会说,这不就是 SQL 联邦查询吗?Trino 不是已经可以把 MySQL、Hive、ClickHouse 当成一张表来查了吗?没错,但 Trino 这种方案解决的只是“查询”层面,而且它自己是执行引擎,需要把数据拉过来自己算。Wayang 的范围更宽——它不仅面向 SQL,还面向 RDD 风格的算子、数据处理管道和机器学习算子;它也不只是“路由整个任务给某个引擎”,而是能在算子粒度上做切分。
另一个容易混淆的对象是 Apache Calcite。Calcite 是做 SQL 解析、校验和优化的通用框架,很多引擎内部用它做优化器。但 Calcite 面向的是“帮你把 SQL 优化成更好的执行计划”,Wayang 面向的是“在多引擎之间选择最优执行者”。如果把 Calcite 比作导航算法,Wayang 就是那个同时管理出租车、地铁、飞机的大调度平台。二者可以结合,但不是同一层的东西。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Apache Wayang 的解耦思路:不造引擎,做引擎指挥层
2.1 核心定位:从“选一个引擎”变成“注册一批引擎”
Wayang 的顶层设计思路其实很朴素:把“数据处理逻辑”和“执行引擎”解耦。你在代码里不直接调用 SparkContext 或 StreamExecutionEnvironment,而是使用 Wayang 提供的统一算子,例如 loadCollection、filter、map、reduceByKey、join、count。这些算子先构成一个平台无关的逻辑计划(WayangPlan),再由 Wayang 内部的优化器把逻辑计划翻译成一到多个平台上的具体执行计划。
用户要做的事情是“注册引擎”。你可以注册一个本地的 JavaStream 插件,也可以注册 Spark、Flink、PostgreSQL 等插件,甚至可以同时注册多个。注册完之后,写业务代码时完全不用关心数据最终跑在哪个引擎上。这个体验很像我第一次用 Spark 时的感觉——把 SparkSession 当成入口,其他都交给框架。但 Wayang 的“Session”背后不是绑定某个固定引擎,而是一组可动态选择的引擎。
这种设计有个很实际的收益:它把“技术选型”这件事从项目初期推迟到了运行时。你今天只注册 JavaStream 和 Spark,明天发现业务需要更合适的引擎,只要新增一个插件,业务代码基本不用动。对于怕选错技术
