[FLINK-36605] Bump debezium to last 2.x version - #4516
Conversation
d676bbf to
22d830b
Compare
278538f to
0fd1336
Compare
85efd93 to
2702e3f
Compare
2702e3f to
4f4547a
Compare
|
Thanks for doing this — the one-minor-per-commit staging makes it reviewable in a way a single I built the same migration separately before finding this PR (same 1.9.8 → 2.7.4 target, same Java 11 1. The Java 11 guarantee does not survive a JDK 17 build machineThis one undercuts the PR's own headline claim, which is why it is first. The root pom sets <profile>
<id>java-17-target</id>
<activation><jdk>[17,)</jdk></activation>
<properties><java.version>17</java.version></properties>
... <source>17</source><target>17</target> ...
</profile>So a release built on a JDK 17 toolchain emits class-file major 61 regardless of the declared Fix that worked for me: have both profiles derive I am happy to send that as a separate small PR so it does not enlarge this one. 2.
|
What is the purpose of this pull request?
Bumps the Debezium dependency from 1.9.8.Final to 2.7.4.Final — FLINK-36605.
The upgrade is staged one minor at a time, as eight commits. Each commit sets a single
<debezium.version>and is independently compilable and testable, so the series can be bisected and reviewed hop by hop rather than as one 160-file diff.2.7.4 is deliberately the end point. Debezium 3.x requires Java 17/21, which would force raising the minimum Java version and evaluating the removal of Flink 1.x. This PR stays on Java 11 / Flink 1.x throughout (verified from the bytecode:
debezium-coreanddebezium-connector-binlog2.7.4 class files are major version 55, anddebezium-build-parentdeclaresjdk.min.version= 11).Brief change log
160 files changed, 8580 insertions(+), 6961 deletions(-)across 8 commits. Referenced by version rather than SHA, since the branch is rebased as review progresses.history→SchemaHistoryrename (database.history.*→schema.history.internal.*);database.server.name→topic.prefix;TopicSelector→TopicNamingStrategy;DataCollectionIdmoved package;*Partitionctors gaineddatabaseName. Solved by a tree-wide config-key/import migration plus re-basing the forks onto 2.0.1; several forks deleted because the bug they patched was fixed upstream.database.server.idbecame.required(), so the MySQL config factory now injects a default.WalPositionLocatorgained anOperationarg and dropped the deaddoSnapshotparam; SqlServer ctor arg →SqlServerJdbcConfiguration; ANTLRColumnDeclarationContext.uid()→.fullColumnName().uid(). Solved by re-basing the two postgres forks plus one-line owned-code fixes.SchemaNameAdjustermovedio.debezium.util→io.debezium.schema(18 files); theSchemaHistoryinterface shrank; emitter ctors gained args;EmbeddedEngineChangeEventgained a 4-arg ctor and a third type param. Solved by import migration and fork re-bases.OffsetContextthreaded through the whole schema-change dispatch path; Kafka Connect 3.5 bump (OffsetBackingStore.connectorPartitions);ErrorHandlergainedreplacedErrorHandler. Solved by updating both owned dispatchers and every fork call site; theMySqlDefaultValueConverterfork was deleted (DBZ-6824 fixed upstream).ChangeEventSourceContextgained 5 abstract methods (blocking snapshot, DBZ-6685);SnapshottingTaskmoved to top level with a 5-arg ctor; snapshot ctors gainedNotificationService;TableChanges.drop(Table)→drop(TableId), with a DROP change now carrying a nullTable. Solved by no-op context methods in 8 implementations, threading the snapshotting task, an emptyNotificationService(notnull—PostgresSnapshotSplitReadTaskinheritsexecuteand dereferences it), and a null-guard when serializing a DROP.MySqlConnection→…mysql.strategy.mysql,GtidSetbecame an interface, and the GTID merge and binlog-position read moved out of the forks. Separately, Debezium demoted jsr305 fromprovidedtoruntime, takingjavax.annotationoff the compile classpath in 4 modules (includingmongodb-cdc, which has no Debezium fork at all). Solved by replacing the oldMySqlConnectionfork with three new ones understrategy.mysql, and declaring jsr305 explicitly in the root pom.SnapshotterServicethreaded through every snapshot and streaming source; the PostgresSnapshotterSPI deleted;getBlockingSnapshottingTaskwentdefault→abstract. Solved by a newSnapshotterServiceFactoryhelper (Debezium builds this insideBaseSourceTask, which Flink CDC never runs), plusvalidateLogPositionadded to the Postgres and Db2 connection forks.debezium-connector-binlogsplit — the shared binlog engine moves to a new artifact and the MySQL connector becomes thin subclasses. Solved by re-targeting the forks intoio.debezium.connector.binlog. Net effect is a smaller fork surface.Cross-cutting notes
MySqlConnection(old location),MySqlDefaultValueConverter,MySqlValueConverters,DefaultValueParserListener,HistorizedRelationalDatabaseConnectorConfig. Added:BinlogSnapshotChangeEventSource,mysql/jdbc/MySqlConnection,mysql/jdbc/MySqlConnectionConfiguration, andoracle/antlr/listener/ColumnDefinitionParserListener.spotless:apply. Every fork header records the version it was copied from and the patches it carries.javap. This catches the failure mode the compiler cannot: a fork missing a signature that Debezium's own precompiled code calls. It found a real one at 2.5.4 —SqlServerStreamingChangeEventSource's constructor gained aNotificationServiceargument, and the un-updated fork would have compiled cleanly and thrownNoSuchMethodErroron the legacy embedded-engine path.SnapshotterServiceFactory(flink-connector-debezium), which builds Debezium 2.6+'s snapshotter service outside the Kafka Connect task lifecycle.Findings that only integration testing caught
Every item below compiled cleanly, passed spotless, passed the unit tests, and passed the
javapbinary-compatibility audit. They were found only by running the full suite, and each is fixed in the hop that introduced it, so every commit remains independently correct.This section is the most useful part of the diff to review, because these are the changes that look arbitrary without the explanation.
encryptdefaultfalse→true.SqlServerValidatorbuilds its JDBC URL by hand and could no longer connect.execute()is a stub that throwsUnsupportedOperationException; the real loop lives inSqlServerChangeEventSourceCoordinator, which Flink CDC never runs. The re-fork inherited the throwing stub.RENAME TABLE, so the old table-id matching never fired and the storedALTERwas never re-emitted.debezium-storage-kafkamissing from the fat jars. Debezium 2.0 moved the Kafka schema history out ofdebezium-core. Building a historized connector'sConfigDefeagerly resolves the default value ofschema.history.internalinConfigDef$ConfigKey.<init>, so the class must be present even though Flink CDC always overrides it.EmbeddedEnginebuilds thatConfigDef, and only the legacyDebeziumSourceFunctionpath usesEmbeddedEngine. Unit tests have the artifact transitively; only the shaded E2E jar did not.TIMESTAMP WITH TIME ZONE. 2.1.4 madeZonedTimestampscale-aware, so it keeps trailing zeros (.00789→.007890). Test expectation updated; the stored value is unchanged.SYS.XMLTYPENPE. 2.2.1 madeFieldNameCacheunconditional; that path callsColumnImpl.equals, which NPEs on thenulltypeName Oracle's DDL parser has always produced for schema-qualified types. Fixed with a new fork adding an explicitSYS.XMLTYPE→Types.SQLXMLbranch.GeneratedMessageV3#isStringEmpty), but the test-scopedmysql-connector-javadrags in 3.11.4, which wins nearest-wins resolution.NoSuchMethodErroris raised on gRPC'sThreadlessExecutor, wherewaitAndDrainswallows it — so the test hangs instead of failing.effectiveOffsetContextNPE. 2.5 routes offset access through a field populated byinit(offsetContext), which Debezium's coordinator calls but Flink CDC does not. The fork patch initialising it was lost in the re-fork.SnapshotterServiceNPE. It resolves the connector-specific snapshotter viaClass.forName(config.getString("connector.class")); Flink CDC assembles its Debezium config by hand and never sets that key.debezium-connector-binlogmissing from the fat jars after the artifact split. Verified against the built jar, confirming both presence and that the fork wins the class overlap.<includes>are not type-checked.time(4)rounding. Bisected to 2.7.4. An earlier hypothesis blaming the mssql-jdbc version was disproved by a live JDBC probe: drivers 9.4.1 and 12.4.2 behave identically.currentMaxLsntocurrentMaxLsn.increment(), making it inclusive. Flink CDC's long-standingDb2Connection.getChangeTables()fork readsstartLsnfrom a column tracking capture progress, sostartLsn == currentMaxLsnon nearly every poll — the same capture instance is queued repeatedly andmigrateTable()re-reads the live table schema each time. After anALTER TABLE ... ADD COLUMNthat installs the new wider schema while the open result set still yields the old column count:Data row is smaller than a column index. The fork restores the exclusive bound, i.e. exactly the pre-2.7 behaviour.Deliberately out of scope: the Db2
getChangeTables()column mapping is left unchanged from master. WhetherstartLsnshould come from a different column is a pre-existing Flink CDC question, not something a version bump should decide.Verifying this change
BinlogOffsetTest,GtidUtilsTest,FilterGtidSetTest— placeholder GTID source ids (aaa-111,A) replaced with real server UUIDs. From Debezium 2.5 the GTID set delegates parsing to the binlog client, which validates ids withUUID.fromString. Test-only: production GTIDs are always UUIDs.FilterGtidSetTestmoved and rewritten to driveMySqlConnection, since 2.5 moved the GTID merge onto the connection.SqlServerEventDeserializerTest—drop(table)→drop(table.id()).OraclePipelineITCase#restartFromSavePoint— see below.SqlServerConnectorITCase#testAllTypes—time(4)expectation, see the findings table.LegacyMySqlSourceITCase,PostgreSQLSourceTest,Db2SourceTest, the[2]variants of the E2E suites) matter most here: they are the only tests that drive the forks through Debezium's own task and coordinator lifecycle, which is where fork mismatches surface. Several findings above were reachable only through that path.One test change worth calling out
OraclePipelineITCase#testSnapshotModeRestartFromSavepointslept a fixed 30 s and then calledstopWithSavepoint. WithStartupOptions.snapshot()the source isBoundedness.BOUNDED, so the job legitimately finishes — andstopWithSavepointcan never succeed on a terminated job. Under 2.x the snapshot completes inside that window.The test now waits until the job is
RUNNINGin snapshot mode (unbounded modes keep the original settle time, so the passingtestInitialModeRestartFromSavepointis untouched), and the retry helper fails fast on a terminal state instead of burning 600 retries and reporting a misleading timeout.IncrementalSource.getBoundedness()is not modified by this PR — the behaviour it encodes is the same on master; only the test's assumption was wrong.MySqlConnectionprobesSHOW BINARY LOG STATUSonce on construction and falls back toSHOW MASTER STATUS. The probe site moved three times across the series as Debezium reorganised the read path (snapshot source → connector adapter → back to snapshot source). Please confirm it is reached on both MySQL 8.0 and 8.4.debezium-connector-mariadb, so this is contained — but it is a wider blast radius than the previous mysql-only forks and deserves a look.PostgresReplicationConnection.validateSlotIsInExpectedStateis overridden to a no-op (since 2.1.4). Debezium callspg_replication_slot_advance(slot, storedLsn)fromstartStreaming; Flink CDC drives the start position from its own incremental-snapshot offsets, so the stored LSN is not a valid advance target and the seek throws, producing a restart loop. Please confirm this is the right call rather than changing the offset we store.NotificationServiceandSnapshotterServiceinstances. Flink CDC does not run Debezium's Kafka Connect task lifecycle, so these are constructed directly with no notification channels registered. Confirm no notification-dependent behaviour is expected.SnapshotterServiceFactorybuilds its own service registry withconnector.classset, rather than reusingconnectorConfig.getServiceRegistry().BinlogStreamingChangeEventSource.executeinitialises the effective offset context when it is null, because Flink CDC never callsinit(...).Debezium 2.0 removed the
MySqlConnectorConfig.GTID_NEW_CHANNEL_POSITIONenum that selected between the EARLIEST reconciliation (GtidUtils.fixOldChannelsGtidSet) and the LATEST path added in FLINK-39149.This PR drives the choice from a pass-through property
gtid.new.channel.position, defaulting toearliest— which matches upstream Debezium 2.0 and preserves the exact pre-bump runtime behaviour, since production Flink CDC code never set the old enum.The question: is it acceptable for the
LATESTpath (FLINK-39149) to be reachable only via the raw Debezium property, or should Flink CDC expose a first-class connector option for it? This is an API-surface question, not a correctness bug. Suggested reviewers: the FLINK-39149 author(s) and MySQL connector maintainers.Documentation
Dependency upgrade only. No public connector option is added or removed. One behavioural surface changes shape — the MySQL GTID new-channel-position selector, see the decision item above — and
docs/may need a note if maintainers choose to expose it as a first-class option.Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code