You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
mysql_cdc: chunk large tables across workers via PK-range splitting
Adds an opt-in snapshot_chunks_per_table field to mysql_cdc. When left at
its default (1) the snapshot flow is unchanged. When set higher, each
table's first primary-key column is probed for MIN and MAX under the
shared consistent-snapshot transaction and the resulting integer range is
split into N half-open chunks that are dispatched across the existing
snapshot_max_parallel_tables worker pool.
This is a follow-up to the inter-table parallelism introduced in the
mysql_cdc: parallelise snapshot reads across tables change. Inter-table
parallelism alone cannot accelerate a snapshot dominated by a single very
large table, which is the most common shape for message/event tables.
Chunking splits that single-table work across the worker pool instead.
Chunking is supported for tables whose first primary-key column is an
integer type (tinyint/smallint/mediumint/int/integer/bigint, signed or
unsigned). Composite primary keys are supported - chunking partitions on
the leading column only, and per-chunk keyset pagination continues to
respect the full PK ordering. Tables with non-numeric first PK columns
fall back to a whole-table read with an informational log line so mixed
workloads keep working.
Consistency model is unchanged. All worker transactions still begin
under one FLUSH TABLES WITH READ LOCK window so every chunk observes
identical state at the same binlog position. Planning runs inside one
worker's snapshot transaction so MIN/MAX agree with what every worker
subsequently reads.
The outermost chunks in each table are open-ended (no lower bound on
the first chunk, no upper bound on the last) so rows at the exact
MIN/MAX endpoints and any rows outside [MIN, MAX] are captured rather
than silently dropped.
The fan-out helper (previously distributeTablesToWorkers) is generalised
to a generic distributeWorkToWorkers so the parallel path can dispatch
chunk-typed work units while the existing fan-out tests keep passing
with string inputs.
Field cap: snapshot_chunks_per_table is validated at config time to be
within [1, 256], matching the pattern established for
snapshot_max_parallel_tables.
Tests added:
- snapshot_chunking_test.go: splitIntRange coverage and overflow,
buildChunkPredicate shapes, and generic fan-out against
snapshotWorkUnit.
- config_test.go: default, explicit, and out-of-range values for
snapshot_chunks_per_table.
- integration_test.go: TestIntegrationMySQLChunkedSnapshot exercises an
int PK table and a composite (int, int) PK table with chunks=8 and
asserts no duplicates across overlapping chunk ranges;
TestIntegrationMySQLChunkedSnapshotNonNumericPKFallback confirms the
VARCHAR-PK fallback reads the whole table without error.
Description("The maximum number of tables that may be snapshotted in parallel. When set to `1` (the default) tables are read sequentially using a single transaction, preserving the previous behaviour. When set higher, multiple `REPEATABLE READ` transactions are opened on separate connections under a single brief `FLUSH TABLES ... WITH READ LOCK` window so every worker observes an identical, globally-consistent snapshot at the same binlog position. A value greater than the number of configured `tables` is effectively capped at the table count. Must be between `1` and `256`.").
125
+
Description("The maximum number of tables that may be snapshotted in parallel. When set to `1` (the default) tables are read sequentially using a single transaction, preserving the previous behaviour. When set higher, multiple `REPEATABLE READ` transactions are opened on separate connections under a single brief `FLUSH TABLES ... WITH READ LOCK` window so every worker observes an identical, globally-consistent snapshot at the same binlog position. Must be between `1` and `256`.").
126
+
Advanced().
127
+
Default(1),
128
+
service.NewIntField(fieldSnapshotChunksPerTable).
129
+
Description("The number of primary-key chunks each table is split into during the snapshot. When set to `1` (the default) each table is read as a single unit. When set higher, each table's first primary-key column is probed for `MIN` and `MAX` and the resulting integer range is split into N equal half-open chunks that are dispatched across the `"+fieldSnapshotMaxParallelTables+"` worker pool. This is how a single very large table is parallelised. Only tables whose first primary-key column is an integer type (`tinyint`, `smallint`, `mediumint`, `int`, `integer`, or `bigint`, signed or unsigned) are chunked; tables with non-numeric first PK columns fall back to a single whole-table read and log the reason. Composite primary keys are supported — chunking uses the leading column only, and per-chunk keyset pagination continues to respect the full PK ordering. Must be between `1` and `256`.").
117
130
Advanced().
118
131
Default(1),
119
132
service.NewIntField(fieldMaxReconnectAttempts).
@@ -198,6 +211,7 @@ type mysqlStreamInput struct {
198
211
checkPointLimitint
199
212
fieldSnapshotMaxBatchSizeint
200
213
fieldSnapshotMaxParallelTablesint
214
+
fieldSnapshotChunksPerTableint
201
215
202
216
logger*service.Logger
203
217
res*service.Resources
@@ -303,6 +317,16 @@ func newMySQLStreamInput(conf *service.ParsedConfig, res *service.Resources) (s
303
317
returnnil, fmt.Errorf("field '%s' must be at most %d, got %d", fieldSnapshotMaxParallelTables, maxSnapshotParallelTables, i.fieldSnapshotMaxParallelTables)
0 commit comments