Apache Texera 1.2.0-incubating 架构与核心概念详解
基于 v1.2.0-incubating 源码树与一次真实编译启动的实测,讲清 Apache Texera 的总体分层、sbt 模块划分、Web 服务角色、amber 执行引擎目录结构与数据存储链路
Apache Texera 1.2.0-incubating 架构与核心概念详解
目标:以 v1.2.0-incubating 源码树(commit c3aa6e4ba36bdd0cdc9f76bd7896c024dda392b3)为底本,配合一次真实的后端编译与启动实测,讲清 Texera 的总体分层、sbt 模块划分、各 Web 服务角色、amber 执行引擎目录结构与数据存储链路。已在 Ubuntu 24.04(x86_64)+ OpenJDK 17.0.20.1 + sbt 1.12.9 + PostgreSQL 16 环境实测通过。
一、环境信息
本篇所有结论均来自对本地源码树的直接检视与真实启动实测,先固定基线:
- 源码版本:v1.2.0-incubating(git describe 输出,commit c3aa6e4ba36bdd0cdc9f76bd7896c024dda392b3,2026-07-30)
- 构建工具:sbt 1.12.9(Scala 2.13.18 编译产物)
- JDK:OpenJDK 17.0.20.1
- 数据库:PostgreSQL 16.15(
sql/texera_ddl.sql初始化,28 条 CREATE TABLE) - 前端:Angular 21(frontend/package.json version=1.2.0-incubating,engines node>=24,packageManager yarn@4.14.1)
- 实测运行产物:
amber/target/universal/stage/bin/下的 4 个启动脚本 - 检视命令示例(实时回显):
cd texera-src && git describe --tags && git log -1 --format="%H %cd" --date=short
v1.2.0-incubating
c3aa6e4ba36bdd0cdc9f76bd7896c024dda392b3 2026-07-30
二、项目定位与总体分层
Texera 是一个可协作的数据分析平台:用户在浏览器里拖拽算子组装工作流,平台把工作流编译成物理计划交给执行引擎分布式运行,结果再以表格或图表回显到前端。整个仓库按职责分成三层:
| 层 | 组成 | 说明 |
|---|---|---|
| 前端层 | frontend/(Angular 21 + TypeScript) | 工作流编辑器、算子面板、结果可视化、协同编辑 UI |
| 服务层 | 12 个子模块中的 7 个 Web 服务 | 登录鉴权、工作流 CRUD、数据集、编译校验、计算单元管理等 REST/WebSocket 服务 |
| 执行层 | amber/(WorkflowExecutionService 模块,amber 引擎) | 把逻辑计划调度到 worker 执行,含容错与日志回放 |
三层之间以 HTTP(/api/*)、WebSocket(/wsapi/*)与数据库(PostgreSQL/Iceberg/S3 协议对象存储)连接。官方开发者文档(docs/contribution-guidelines/guide-for-developers.md)明确给出了各服务的分工表,本篇第四章逐项对照实测。
💡 技术拓展:同类数据科学平台中,JupyterHub 偏重单用户交互式 Notebook 会话分发,Apache Zeppelin 偏重解释器制的 Notebook 分析,而 Texera 的差异点在于「工作流 + 多算子图 + 协同编辑 + 分布式执行引擎」的组合:它把分析过程显式建模为有向图并交由 amber 引擎调度执行,本系列文章即以 Texera 1.2.0-incubating 为准。
三、代码仓库与 sbt 模块划分
仓库根 build.sbt 用 lazy val 声明了各模块。实测 grep -nE "lazy val [A-Za-z]+ \(project" build.sbt 的结果(节选):
112:lazy val DAO = (project in file("common/dao")).settings(asfLicensingSettings)
113:lazy val Config = (project in file("common/config")).settings(asfLicensingSettings)
114:lazy val Auth = (project in file("common/auth"))
117:lazy val ConfigService = (project in file("config-service"))
126:lazy val AccessControlService = (project in file("access-control-service"))
140:lazy val PyBuilder = (project in file("common/pybuilder"))
145:lazy val WorkflowCore = (project in file("common/workflow-core"))
150:lazy val ComputingUnitManagingService = (project in file("computing-unit-managing-service"))
165:lazy val FileService = (project in file("file-service"))
179:lazy val WorkflowOperator = (project in file("common/workflow-operator")).settings(asfLicensingSettingsWithVendored).dependsOn(WorkflowCore)
180:lazy val WorkflowCompilingService = (project in file("workflow-compiling-service"))
192:lazy val WorkflowExecutionService = (project in file("amber"))
213:lazy val TexeraProject = (project in file("."))
按依赖关系可以归为四类:
| 类别 | 模块 | 职责 |
|---|---|---|
| 基础库 | DAO、Config、Auth、PyBuilder | 数据库访问(jOOQ 生成代码)、配置加载、JWT 鉴权、Python 执行器构建 |
| 领域库 | WorkflowCore、WorkflowOperator | 工作流逻辑计划核心模型、全部算子描述符(LogicalOp 及其子类) |
| Web 服务 | ConfigService、TexeraWebApplication(amber 内)、FileService、WorkflowCompilingService、ComputingUnitManagingService、AccessControlService | 对前端暴露 REST/WebSocket 接口 |
| 可执行体 | WorkflowExecutionService(amber) | 既包含 TexeraWebApplication 主服务,也包含 ComputingUnitMaster/Worker 执行角色 |
一次真实的后端全量编译(sbt compile,首编译 82 秒,不含依赖下载)实测回显节选:
[info] compiling 258 Scala sources and 50 Java sources to /work/texera-src/common/workflow-operator/target/scala-2.13/classes ...
[info] compiling 9 Scala sources to /work/texera-src/computing-unit-managing-service/target/scala-2.13/classes ...
[info] done compiling
[warn] two warnings found
[success] Total time: 82 s (0:01:22.0)
⚠️ 注意:sbt 编译的模块日志按依赖序展开,
common/workflow-operator是体量最大的模块(258 个 Scala 源文件),首次冷编译的时间主要花在这里与 amber 模块。
四、Web 服务角色与端口
官方开发者指南给出了每个服务的角色定位,实测对照如下(翻译整理自 docs/contribution-guidelines/guide-for-developers.md 第 197-204 行的服务表):
| 服务 | 源码位置 | 角色 | 实测状态 |
|---|---|---|---|
| ConfigService | config-service/ | 向前端提供系统配置数据 | 编译通过,本地单机模式非必需 |
| TexeraWebApplication | amber/.../web/TexeraWebApplication.scala | 用户登录、社区资源读写、算子元数据加载 | 实测启动成功,8080/8081 监听 |
| FileService | file-service/ | 数据集管理、访问控制与读写 | 编译通过 |
| WorkflowCompilingService | workflow-compiling-service/ | 工作流构建期传播 schema 并做静态检查 | 编译通过 |
| ComputingUnitMaster | amber/.../web/ComputingUnitMaster.scala | 工作流执行主节点 | 官方要求先于 Worker 启动 |
| ComputingUnitWorker | amber/.../web/ComputingUnitWorker.scala | 计算集群中的 worker 节点(非 Web 服务) | stage 产物含启动脚本 |
| ComputingUnitManagingService | computing-unit-managing-service/ | 管理各类型计算单元的生命周期与连接 | 编译通过 |
| AccessControlService | access-control-service/ | 计算单元请求鉴权,仅 Kubernetes 部署需要 | 本地开发可不启动 |
TexeraWebApplication 是 Dropwizard 应用:Jetty 承载 8080(应用)与 8081(管理)两个端口,Jersey 挂载 /api/* 前缀,WebSocket 端点 /wsapi/collab 由 CollaborationResource 以 @ServerEndpoint 注解提供(协同编辑通道)。端口定义在 amber/src/main/resources/web-config.yml:
server:
applicationContextPath: /
applicationConnectors:
- type: http
port: 8080
adminConnectors:
- type: http
port: 8081
TexeraWebApplication.scala 第 129-163 行依次 register 了 24 个 Jersey 资源,实测摘录如下(按源码顺序):
environment.jersey.register(classOf[SessionHandler])
environment.jersey.register(classOf[SystemMetadataResource])
environment.jersey.register(classOf[HealthCheckResource])
environment.jersey.register(classOf[AuthResource])
environment.jersey.register(classOf[GoogleAuthResource])
environment.jersey.register(classOf[UserConfigResource])
environment.jersey.register(classOf[AdminUserResource])
environment.jersey.register(classOf[PublicProjectResource])
environment.jersey.register(classOf[WorkflowAccessResource])
environment.jersey.register(classOf[WorkflowResource])
environment.jersey.register(classOf[HubResource])
environment.jersey.register(classOf[UserResource])
environment.jersey.register(classOf[WorkflowVersionResource])
environment.jersey.register(classOf[ProjectResource])
environment.jersey.register(classOf[ProjectAccessResource])
environment.jersey.register(classOf[WorkflowExecutionsResource])
environment.jersey.register(classOf[DashboardResource])
environment.jersey.register(classOf[GmailResource])
environment.jersey.register(classOf[AdminExecutionResource])
environment.jersey.register(classOf[UserQuotaResource])
environment.jersey.register(classOf[AdminSettingsResource])
environment.jersey.register(classOf[AIAssistantResource])
environment.jersey.register(classOf[HuggingFaceModelResource])
启动后 8081 管理端口内置 Dropwizard 健康检查,实测回显:
curl -s http://localhost:8081/healthcheck
{"deadlocks":{"healthy":true}}
五、amber 执行引擎结构
amber(WorkflowExecutionService 模块)的引擎代码位于 amber/src/main/scala/org/apache/texera/amber/engine/,实测目录树如下:
engine/
├── architecture/
│ ├── common/
│ ├── controller/
│ ├── deploysemantics/
│ ├── logreplay/
│ ├── messaginglayer/
│ ├── pythonworker/
│ ├── scheduling/
│ ├── sendsemantics/
│ └── worker/
└── common/
├── ambermessage/
├── client/
├── rpc/
├── statetransition/
├── storage/
└── virtualidentity/
各子目录职责:
messaginglayer:actor 消息层,封装节点间通信与序号去重。controller:执行控制器,驱动工作流状态机、区域终止与恢复决策。worker:单个算子实例(WorkerActor)的执行与状态迁移。deploysemantics:算子实例的部署语义(单实例、按分区并行等)。sendsemantics:数据分发的传输语义(one-to-one、all-to-all 等批量发送策略)。logreplay:故障恢复所依赖的日志回放机制。scheduling:工作流级别的调度策略。pythonworker:与 Python 执行器(PyBuilder 构建)之间的跨语言桥接。common/virtualidentity:全链路虚拟身份(execution/operator/worker 各级 ID)。
sbt "WorkflowExecutionService/stage" 打包后产生 4 个可执行入口(实测 ls amber/target/universal/stage/bin/ 回显):
amber
amber.bat
computing-unit-master
computing-unit-master.bat
computing-unit-worker
computing-unit-worker.bat
texera-web-application
texera-web-application.bat
对应关系:texera-web-application 启动第四章的 Web 服务;computing-unit-master/computing-unit-worker 启动执行主节点与 worker;amber 入口保留给单进程模式。
六、数据与存储链路
Texera 的持久化分两条线:关系型元数据与工作流结果/数据集对象。
6.1 关系型元数据(PostgreSQL + jOOQ)
common/config/src/main/resources/storage.conf 第 138 行定义了主库连接(原文节选):
url = "jdbc:postgresql://localhost:5432/texera_db?currentSchema=texera_db,public"
数据库与 schema 由 sql/texera_ddl.sql 一次性创建(先 DROP/CREATE DATABASE texera_db,再 CREATE SCHEMA texera_db,随后 28 条 CREATE TABLE 建齐用户、工作流、项目、执行等表,并在第 439 行起创建 pgroonga 扩展与全文索引辅助函数)。sbt 模块 DAO 在编译前运行 DAO/jooqGenerate,从该库反向生成 jOOQ 代码到 common/dao/target/src_managed,运行期由 Hikari 连接池管理连接(启动日志实测出现 texera-hikari - Start completed.)。
6.2 工作流结果(Apache Iceberg)
storage.conf 的 storage.iceberg 段配置结果表存储,catalog.type 支持 hadoop、rest、postgres 三种,默认 postgres,指向 localhost:5432/texera_iceberg_catalog(由 sql/iceberg_postgres_catalog.sql 初始化)。结果按命名空间分表:operator-port-result(端口数据)、operator-console-messages(控制台消息)、workflow-runtime-statistics(运行统计)、operator-port-state(状态)。
6.3 数据集与对象存储(LakeFS + S3 协议)
storage.conf 的 storage.lakefs 段定义数据集版本化存储(默认 http://localhost:8000/api/v1,示例密钥 AKIAIOSFOLKFSSAMPLES),块存储类型 s3、桶名 texera-dataset;storage.s3 段定义对象存储端点(默认 http://localhost:9000)、大对象桶 texera-large-binaries 与 16MB 分片上传尺寸。
6.4 配置覆盖约定
storage.conf 中每一项都重复声明了一次 =${?STORAGE_...} 形式的 HOCON 环境变量回退,例如 type = ${?STORAGE_ICEBERG_CATALOG_TYPE}。这意味着所有存储配置都可以不改动文件、仅通过 STORAGE_ 前缀环境变量覆盖,这是多环境部署与编排化部署的统一入口。其余配置文件:web-config.yml(端口与日志)、gui.conf(前端参数)、user-system.conf(用户系统)、udf.conf(Python 解释器路径)。
七、前端与工作流模型
前端为 Angular 21 单页应用,构建产物 frontend/dist(实测 39 MB,入口 index.html 18420 字节,页面内嵌版本戳 build-version: 1.2.0-incubating.261015373)。服务层通过 FileAssetsBundle 把该目录作为静态资源挂载到根路径,启动日志实测:
Registering FileAssetBundle with servlet name file-assets for request path /* from file system /work/texera-src/amber/../../frontend/dist
注意该路径是相对启动目录的 ../../frontend/dist 推导,因此独立运行 stage 产物时若目录相对关系不成立,静态页面会 404(详见第九章)。
工作流的持久化形态是一份 JSON。仓库自带的示例 bin/single-node/examples/workflows/[Example] Data Exploration on Movies Dataset.json 实测解析出的顶层结构:
top keys: ['operators', 'operatorPositions', 'links', 'commentBoxes', 'settings']
单个算子对象与一条连线(link)的字段(同一文件实测):
operator keys: ['operatorID', 'operatorType', 'operatorVersion', 'operatorProperties',
'inputPorts', 'outputPorts', 'showAdvanced', 'isDisabled',
'customDisplayName', 'dynamicInputPorts', 'dynamicOutputPorts', 'viewResult']
operator sample: {"operatorID": "CSVFileScan-operator-ddb8baf2-...", "operatorType": "CSVFileScan",
"customDisplayName": "Read Movie Dataset"}
link sample: {"linkID": "3fba9036-...", "source": {"operatorID": "Aggregate-operator-...", "portID": "output-0"},
"target": {"operatorID": "PieChart-operator-...", "portID": "input-0"}}
字段要点:operatorType 决定反序列化到哪个算子描述符类(类型注册机制见本系列算子篇);operatorProperties 是该算子的参数键值对,与算子元数据里的 JSON Schema 对应;operatorPositions/commentBoxes/settings 只服务画布呈现,执行引擎不消费。
八、一次完整启动的实测时序
以下是 stage 产物在已就绪的 PostgreSQL 之上冷启动的完整时序(日志时间戳均为实测值):
[12:43:12,848] Registering FileAssetBundle with servlet name file-assets for request path /* from file system /work/texera-src/amber/../../frontend/dist
[12:43:13,355] [com.zaxxer.hikari.HikariDataSource] texera-hikari - Start completed.
[12:43:14,142] [io.dropwizard.server.ServerFactory] - Starting TexeraWebApplication
[12:44:00,990] Started i.d.j.MutableServletContextHandler@16f62062{/,null,AVAILABLE}
[12:44:01,010] Started application@7846913f{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
[12:44:01,014] Started admin@48da64f2{HTTP/1.1,[http/1.1]}{0.0.0.0:8081}
[12:44:01,014] [org.eclipse.jetty.server.Server] - Started @4302ms
启动后约 4302 毫秒 Jetty 完成绑定,进程 RSS 实测约 410 MB(-J-Xmx512m 参数下)。随后逐项验证核心 API(实测回显):
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080/api/resources/operator-metadata
200
curl -s -X POST -H "Content-Type: application/json" \
-d '{"username":"doc_writer","password":"q1w2e3r4"}' \
http://localhost:8080/api/auth/register
{"accessToken":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJkb2Nfd3JpdGVyIiwidXNlcklkIjozLCJnb29nbGVJZCI6bnVsbCwiZW1haWwiOiJkb2Nfd3JpdGVyIiwicm9sZSI6IlJFU1RSSUNURUQiLCJnb29nbGVBdmF0YXIiOm51bGwsImV4cCI6MTc5MjY3MjkyMH0.ay-4_EStOtpyy91X7563ndxg6nM8z3fOoUVz7K-cjwU"}
首次注册即返回 JWT accessToken(新用户角色为 RESTRICTED,JWT 载荷内 role 字段可解码确认);同一用户名重复注册返回 406 与 {"code":406,"message":"Username exists already."};登录接口 POST /api/auth/login 同样返回 200 与新签发的 JWT。
九、注意事项与常见问题
9.1 stage 模式下静态页面 404 是已知边界
FileAssetsBundle 注册的静态目录是相对启动目录上两级推导的(../../frontend/dist)。以 stage 产物独立启动时该相对路径不指向真实 dist,实测 GET / 返回 404,同时 /api/* 一切正常;将 stage 目录软链到 frontend/dist 后重启仍为 404。结论:静态 GUI 服务面向开发模式(在仓库内目录启动,或 IDE 直接运行主类);独立部署应确保目录相对关系与仓库布局一致,或以反向代理托管前端静态文件。
9.2 启动日志中的 jgit 异常可以忽略
启动早期会出现一段 org.eclipse.jgit.errors.RepositoryNotFoundException: repository not found: /work/texera-src/amber 的堆栈,来自 OPVersion 尝试从当前工作目录向上定位 git 仓库以读取算子版本号。该异常被捕获后进程继续启动,API 全部可用,不影响功能;如希望消除,可在仓库根目录启动。
9.3 未配置 user-sys.domain 会出现横幅告警
启动日志实测出现:
[WARN] The user-sys.domain is not configured, and the "Sent from:" field in the email will not include a domain!
Please configure user-sys.domain=your.domain.com or set the environment variable/system property USER_SYS_DOMAIN
仅影响邮件外发域名的显示,本地验证可忽略;生产部署建议配置该环境变量。
9.4 缺少 jOOQ 生成代码时编译报 27 个错误
跳过 DAO/jooqGenerate 直接 sbt compile 会集中报 object jooq is not a member of package org.apache.texera.dao(实测 27 errors)。另外注意:数据库不可达时 DAO/jooqGenerate 任务本身以 [warn] JOOQ code generation failed: Connection to localhost:5432 refused 告终但 sbt 退出码为 0,不能以退出码判断该步成败,需回看日志。
9.5 首次编译会出现 protoc 告警
实测日志:[warn] protoc or protoc-gen-python_betterproto not found on PATH; skipping Python proto generation.。这只影响 Python 执行器的 proto 重生成,Java/Scala 编译与 Web 服务启动不受影响。
十、参考链接
- Apache Texera 官网:
https://texera.apache.org/ - 源码仓库:
https://github.com/apache/texera(tag v1.2.0-incubating) - 开发者指南(服务角色表与本地启动说明):仓库内
docs/contribution-guidelines/guide-for-developers.md - 存储配置说明:仓库内
common/config/src/main/resources/storage.conf - Web 端口与日志配置:仓库内
amber/src/main/resources/web-config.yml - 数据库 DDL:仓库内
sql/texera_ddl.sql、sql/iceberg_postgres_catalog.sql - Apache 软件基金会孵化器声明:
https://incubator.apache.org/