-
Notifications
You must be signed in to change notification settings - Fork 512
docs: draft MySQL snapshot parallelism page #38091
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| --- | ||
| headless: true | ||
| --- | ||
|
|
||
| Materialize parallelizes snapshotting across the workers of the cluster | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since we don't parallelize everything (sql server), I would make it more "can" and separate out. I think something like (?): I might have misinterpreted something ... but, hopefully, the above can give a gist of what I'm thinking
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adopted your structure, thanks. Only tweak: split the PG bullet's fallback clause into its own sentence. |
||
| hosting the source. For PostgreSQL and MySQL sources, work is distributed by | ||
| table, with different tables read concurrently by different workers. | ||
| PostgreSQL sources additionally partition every table, splitting its read | ||
| across workers (on PostgreSQL 14 and later). MySQL sources partition tables | ||
| that meet certain requirements. See [MySQL snapshot | ||
| parallelism](/ingest-data/mysql/snapshot-parallelism/). Kafka sources are | ||
| parallelized by topic partition, with partitions distributed across workers, | ||
| so parallelism is bounded by the topic's partition count. SQL Server sources | ||
| are not parallelized: a single worker reads all tables. | ||
|
|
||
| A cluster's [size](/sql/create-cluster/#available-sizes) determines its | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adopted. |
||
| number of workers, so a larger cluster shortens the snapshot. The volume | ||
| read from the upstream database is unchanged, it is compressed into a | ||
| shorter window of more concurrent queries and connections. To tell whether | ||
| the upstream database is struggling under this load, and for options if it | ||
| is, see [Is the upstream database | ||
| overloaded?](/ingest-data/troubleshooting/#is-the-upstream-database-overloaded) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| --- | ||
| title: "Snapshot parallelism" | ||
| description: "How Materialize splits the snapshot of a single MySQL table across the workers of a cluster." | ||
| menu: | ||
| main: | ||
| parent: "mysql" | ||
|
kay-kim marked this conversation as resolved.
|
||
| name: "Snapshot parallelism" | ||
| identifier: "mysql-snapshot-parallelism" | ||
| weight: 70 | ||
| --- | ||
|
|
||
| When you create a [MySQL source](/sql/create-source/mysql-v2/), Materialize | ||
|
kay-kim marked this conversation as resolved.
|
||
| performs an initial, snapshot-based sync of the selected tables before it | ||
| starts ingesting change events from the binlog. For large tables, this | ||
| snapshot dominates the time until the source becomes healthy. | ||
|
|
||
| How snapshot work is spread across the workers of a cluster, and what that | ||
| means for the upstream database, is covered in | ||
| [Snapshotting](/concepts/snapshotting/#parallelism). This page covers what is | ||
| specific to MySQL: Materialize can split the read of a **single table** | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So ... this content is mysql specific ... but the splitting the reads ... that's not specific to mysql as postgres14+ can do it yes?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair point. Reworded the intro so table splitting isn't claimed as MySQL-only, and the page now scopes itself to what is: the eligibility rules and the prefix-based partitioning. |
||
| across all the workers of the cluster, so that even a source dominated by one | ||
| very large table benefits from a larger cluster. | ||
|
|
||
| ## Which tables are split | ||
|
|
||
| The snapshot of an individual table is split across workers when all of the | ||
| following hold: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ? Materialize splits the snapshot of an individual table across workers when all of the following conditions are met:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adopted. |
||
|
|
||
| - The table has a **single-column primary key**. Composite primary keys are | ||
| not supported. | ||
| - The primary key column is of type **`CHAR` or `VARCHAR`**, with a declared | ||
| length of **at most 768 characters**. Other types, including numeric keys, | ||
| are not supported. | ||
| - The primary key column uses the **`utf8mb4` character set** with the | ||
| **`utf8mb4_bin` collation**. | ||
| - The table is **large enough to be worth splitting**. Small tables are read | ||
| by a single worker, where splitting would add overhead without benefit. | ||
|
|
||
| How evenly the split lands also depends on the distribution of the key | ||
| values. See [How a table is partitioned](#how-a-table-is-partitioned). | ||
|
|
||
| Tables that don't meet these requirements, or whose boundary sampling fails | ||
| for any reason, still snapshot correctly: each is read in full by a single | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we simplify and add a link to the boundary sampling? If a table does not meet these requirements, or if the boundary sampling fails,
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adopted, with one extra sentence noting that different tables are still read concurrently. |
||
| worker, and different tables are still read concurrently. | ||
|
|
||
| ## How a table is partitioned | ||
|
|
||
| Materialize partitions a table by the unique leading characters of its | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. an eligible table and maybe separate with a little tweak? Materialize partitions an eligible table using the Each worker then reads only its assigned range, within the same
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adopted your two-paragraph version. |
||
| primary keys. Before reading the table, it probes the primary key index to | ||
| discover key prefixes and uses the MySQL optimizer's row estimates to gauge | ||
| how many rows fall under each one, extending prefixes until it finds | ||
| boundaries that divide the table into roughly even ranges. The probes are | ||
| inexpensive point lookups, capped in proportion to the table's estimated | ||
| size, so this sampling phase stays negligible next to the snapshot itself. | ||
| Each worker then reads only its assigned range, within the same consistent | ||
| snapshot of the upstream database, so the result is identical to a | ||
| single-worker snapshot, only faster. | ||
|
|
||
| Because partitioning is based on key prefixes and optimizer estimates, how | ||
| evenly the work divides depends on the shape of your keys: | ||
|
|
||
| - **Evenly distributed keys partition well.** Keys whose leading characters | ||
| spread rows uniformly, such as UUIDs, hashes, or other randomized | ||
| identifiers, produce well-balanced ranges. | ||
|
|
||
| - **Skewed keys partition less evenly.** If a large share of the table's rows | ||
| sort under a few common prefixes, some ranges end up with more rows than | ||
| others, and the workers assigned to them finish later. | ||
|
|
||
| - **The probe budget can run out.** If finding even boundaries would require | ||
| examining very many distinct prefixes, Materialize stops probing and uses | ||
| the coarser boundaries found so far, which can also leave ranges uneven. | ||
|
|
||
| Uneven partitioning is never incorrect. It only reduces the speedup, since | ||
| the snapshot finishes when the busiest worker finishes. | ||
|
|
||
| ## MySQL-specific upstream considerations | ||
|
|
||
| - **Connection count.** While the snapshot is being set up, Materialize | ||
| briefly holds up to two connections per worker, plus one. Once reading is | ||
| underway, this settles to one connection per worker reading a range, plus | ||
| one coordination connection. After the snapshot completes, the source drops | ||
| back to a single replication connection. If your MySQL server or connection | ||
| pooler enforces a low | ||
| [`max_connections`](https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_max_connections) | ||
| limit, account for this burst when sizing it. | ||
|
|
||
| - **Statistics freshness.** Range boundaries are placed using the MySQL | ||
| optimizer's row estimates. Stale statistics don't affect correctness, but | ||
| can skew how evenly work divides across workers. Running | ||
| [`ANALYZE TABLE`](https://dev.mysql.com/doc/refman/8.0/en/analyze-table.html) | ||
| on very large tables before creating the source can improve balance. | ||
|
Comment on lines
+84
to
+98
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd keep these here for now: both bullets only apply when parallel snapshotting is active, which is private preview and flag-off, so they'd be noise in the general MySQL considerations. Worth revisiting when the feature is on by default. |
||
|
|
||
| For general guidance on read load, IOPS, and other upstream impact, which is | ||
| not specific to MySQL, see [Is the upstream database | ||
| overloaded?](/ingest-data/troubleshooting/#is-the-upstream-database-overloaded) | ||
|
|
||
| ## Observability | ||
|
|
||
| The progress of an ongoing snapshot is visible in the | ||
| [`mz_internal.mz_source_statistics`](/reference/system-catalog/mz_internal/#mz_source_statistics) | ||
| system catalog view: `snapshot_records_known` is the estimated total size of | ||
| the snapshot and `snapshot_records_staged` is how much of it has been read so | ||
| far. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ? Since we already have https://materialize.com/docs/ingest-data/monitoring-data-ingestion/#monitoring-the-snapshotting-progress ... should we just point them to it?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, replaced the restated catalog details with a pointer to that section. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -99,6 +99,32 @@ also be necessary to support increased memory usage during the process. For more | |
| information, see [Use a larger cluster for upsert source | ||
| snapshotting](/ingest-data/#use-a-larger-cluster-for-upsert-source-snapshotting). | ||
|
|
||
| ## Is the upstream database overloaded? | ||
|
|
||
| Snapshotting puts significant load on the upstream database (see [Impact on | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. puts -> can put a ?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. Made it "Snapshotting can put significant load" |
||
| upstream system](/concepts/snapshotting/#impact-on-upstream-system)). | ||
|
|
||
| Check the upstream database when a snapshot progresses more slowly than the | ||
| data volume suggests, when applications sharing the database slow down while | ||
| it runs, or when the source reports upstream connection errors or timeouts. | ||
| The relevant metrics are in your cloud provider's monitoring console, or in | ||
| OS tools like `iostat` and the database's activity views for self-hosted | ||
| databases. Look for: | ||
|
|
||
| - **CPU** pinned at the instance's limit for the duration of the snapshot. | ||
| - **Read IOPS or throughput** flat at a provisioned cap while disk queue | ||
| depth and read latency climb. | ||
| - **Network throughput** at the instance type's cap. | ||
| - **Memory** pressure, or a falling cache hit rate as large scans evict the | ||
| normal workload's working set. | ||
| - **Connections** near the database's limit. Snapshotting opens connections | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The snapshotting sentence isn't true/applicable for kafka and sql server, yes?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right. Scoped the bullet to PostgreSQL and MySQL sources. |
||
| in proportion to the source cluster's workers. | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we also add (?) Also monitor disk usage during long-running snapshots. For CDC database sources
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a sentence there, pointing at the change-log retention bullet on the snapshotting concept page instead of duplicating it. |
||
| If the database is overloaded, snapshot during off-peak hours, ingest from a | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For an ongoing snapshot, is your recommendation to abort the process and schedule recreating the new source off-peak hours?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that's the recommendation here. Will clarify. |
||
| read replica, use a smaller source cluster to spread the load over a longer | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for read replica ... is this only for Postgres? since we only have a guide for that. (technically feasible for Mysql (?) but we just haven't documented, so ...)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's only postgres. Going to skip that recommendation for now for simplicity though since it's not very general. |
||
| window, [limit the volume of data](/ingest-data/#limit-the-volume-of-data) | ||
| you sync, or provision more IOPS, throughput, or instance capacity. | ||
|
|
||
| ## Adding a new subsource to an existing source blocks replication. Should I just create a new source instead? | ||
|
|
||
| It depends. Materialize provides transactional guarantees for subsource of the | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
? Is it more?
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adopted the total-vs-peak framing.