88fantasy opened a new pull request, #4498:
URL: https://github.com/apache/streampark/pull/4498
## What is the purpose of the change
StreamPark emits no data lineage today. This adds table-level lineage
reporting for Flink SQL and Spark applications as OpenLineage run events, sent
to an Apache Gravitino server's `POST /api/lineage`.
Closes #4495
**Disabled unless configured.** Nothing is injected and nothing is emitted
while `lineage.gravitino.address` is empty, so an existing deployment is
unaffected until an operator configures it — deliberate, since injecting
listener configuration for a jar the cluster's `lib/` does not have would break
job startup.
## Brief change log
**Configuration** — four new system settings (`lineage.gravitino.address`,
`.token`, `.namespace`, `lineage.flink.native.listener.enable`), a
`LineageConfig` bean, and a `lineage_enable` column on `t_flink_app` /
`t_spark_app` for per-application opt-in.
**Flink lineage extraction** — `FlinkSqlLineageExtractor` (one per shims
base, v1 and v2) plans the job's SQL in a throwaway `TableEnvironment` inside
the per-version shims classloader, reached through the existing
`FlinkShimsProxy` — the same mechanism `FlinkSqlServiceImpl.verifySql` already
uses. `CompiledPlanLineageParser` then walks the plan JSON from each
`dynamicTableSink` backwards over `edges` to the sources that reach it.
Two design points worth review:
- **Extraction runs in the console, not in the job.** StreamPark submits
application-mode jobs detached, so a `JobListener` registered inside the job
would never fire `onJobExecuted`, and Gravitino only promotes a run to the
current topology on COMPLETE — a START-only stream never updates the graph.
Emitting all three events from the console's own state machine keeps the
lifecycle correct and leaves the `FlinkStreaming`/`FlinkTable` contract and the
job runtime untouched.
- **Inputs are paired per sink, not flattened.** A `STATEMENT SET` job with
N independent INSERTs compiles to N disconnected subgraphs; flattening the plan
into a single input/output set would report N×M edges that do not exist.
**Dataset identity** — `DatasetIdentityRegistry` maps a connector's `WITH`
options to the `(namespace, name)` pair, and catalog-backed tables resolve from
the plan's qualified identifier. These strings must match other producers into
the same Gravitino instance byte-for-byte: datasets are deduplicated by exact
string, so a mismatch does not fail loudly, it silently splits one physical
table into two graph nodes. Unknown connectors are skipped with a WARN rather
than given a guessed generic fallback.
**Spark lineage** — OpenLineage's Spark listener is configured through
`appProperties`, never overriding a key the user set explicitly.
**Fail-open throughout** — an unresolvable dataset, a plan that will not
compile, an unreachable Gravitino: each logs and continues. A lineage gap must
never fail a job submission.
## Verifying this change
End-to-end against a real Flink 1.20.4 standalone cluster, with a two-sink
mysql-cdc -> Paimon job, verified directly against the lineage backend's own
tables rather than StreamPark's logs:
- Per-sink splitting produced exactly 2 edges, not 2×2.
- **No twin nodes**: the run added only the 2 new sink datasets; it reused
the existing source dataset rows written by another producer, which is the
whole point of the identity rules.
- START and COMPLETE both landed, both runs reached a terminal `COMPLETE`
state, and the graph generation advanced with `stale: false`.
- Run IDs recomputed independently matched the stored ones byte-for-byte.
- Fail-open confirmed both ways: an unknown connector (datagen -> print) and
an unreachable Gravitino address each left the job submitting and finishing
normally, with only WARN/ERROR logs.
Unit tests: `streampark-flink-shims-base` 27 tests,
`streampark-console-service` 115 tests, all passing. The regression guard for
the batch-mode point below was checked by reverting the fix and confirming the
test fails.
Both database upgrade scripts were verified by applying the previous
release's schema, running the upgrade, and diffing against a fresh install —
identical columns and `t_setting` rows on MySQL and PostgreSQL.
## Known limitations
- **Flink 2.x is not covered yet.** Extraction itself is version-agnostic,
but a Flink 2.x SQL job cannot currently be submitted on REMOTE mode at all
(the console bundles a fixed baseline Flink, and Flink resolves
`org.apache.flink.*` parent-first). That is a separate architectural issue, not
specific to lineage.
- **Table-level only**, no column-level lineage.
- The optional native `openlineage-flink` listener requires Flink 1.19+ and
the jar in the cluster's `lib/`; it is off unless the address is set.
- The PostgreSQL upgrade script covers `t_flink_app` only, because
`pgsql-schema.sql` defines no Spark tables at all — a pre-existing gap this PR
neither widens nor fixes.
## Does this pull request potentially affect one of the following parts
- Dependencies (does it add or upgrade a dependency): **yes**
- Adds `io.openlineage:openlineage-java` 1.29.0 (Apache-2.0).
- Upgrades `httpclient5` 5.1 -> 5.4.2 and pins `httpcore5`/`httpcore5-h2`
to 5.4.3, which that client requires. Without the explicit pin, an older
transitive `httpcore5` wins mediation and `httpclient5` fails at runtime with
`NoSuchMethodError`. Happy to split this out if maintainers would rather review
the HTTP client bump separately.
- Adds `jackson-databind` to `streampark-flink-shims-base` for parsing the
plan JSON.
- The public API: **no**
- The runtime per-record code paths (performance sensitive): **no** —
nothing is added to the job runtime; extraction happens once per submission in
the console.
- Anything that affects deployment: **yes** — new `t_setting` rows and a new
column on `t_flink_app`/`t_spark_app`, with upgrade scripts for both MySQL and
PostgreSQL.
## Documentation
- Does this pull request introduce a new feature? **yes**
- If yes, how is the feature documented? Configuration is surfaced in the
system settings UI with descriptions, and the classes carry javadoc covering
the design decisions above. Happy to add website documentation if maintainers
want it in this PR.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]