Skip to content
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

Binlog: Improve ZstdInMemoryDecompressorMaxSize management #17220

Merged

Conversation

mattlord
Copy link
Contributor

@mattlord mattlord commented Nov 13, 2024

Description

Vitess supports MySQL's binlog transaction compression. That support lives primarily in a single file: https://github.com/vitessio/vitess/blob/main/go/mysql/binlog_event_compression.go

There's an important variable which controls HOW that work is done. That variable is currently a const:

// At what size should we switch from the in-memory buffer
// decoding to streaming mode which is much slower, but does
// not require everything be done in memory.
zstdInMemoryDecompressorMaxSize = 128 << (10 * 2) // 128MiB

That is currently hardcoded at 128MiB, which was somewhat arbitrary. The thinking was that all transactions will be compressed and you want to process them as fast as possible, while still being able to support payloads of virtually any size — the compressed transaction payload is limited by MySQL's max_allowed_packet size, but the size of the uncompressed payload is not strictly limited.
The in-memory buffer based decoding is fast but memory intensive, so the 128MiB threshold can be too high for environments that are memory constrained (e.g. 512MiB of memory or less). This PR makes this setting configurable via a vttablet flag — --binlog-in-memory-decompressor-max-size — so that it can be configured at the vttablet level based on the details of the execution environment for the process.

Note

This PR also changes how we handle the larger payloads. In local testing done for this PR I realized that the MaxMemory and/or MaxWindowSize options (same for streaming) that were added in v21+ via #16328 means that we CANNOT process compressed payloads which have an uncompressed size larger than the given size (example here). So this PR moves to this for the streaming method:
zstd.NewReader(nil, zstd.WithDecoderLowmem(true), zstd.WithDecoderConcurrency(1))
Which allows us to process the large payload (> ZstdInMemoryDecompressorMaxSize), no matter the size, but using the least amount of memory possible as it instructs the reader to limit memory allocations and limit it to 1 in flight window or block.

It's for this reason that, while this isn't the kind of thing we would normally backport (a new flag), the new flag and the noted change above are critical for those using MySQL with --binlog_transaction_compression. And the zstd.WithDecoderMaxMemory usage is new in v21 via #16328 so I think we should backport this to v21. You can see the failure users could encounter w/o it on main here: https://gist.github.com/mattlord/17c7dbf7985b8805bb6db3efcbaf2218

Related Issue(s)

Checklist

@mattlord mattlord added Type: Enhancement Logical improvement (somewhere between a bug and feature) Component: VReplication labels Nov 13, 2024
Copy link
Contributor

vitess-bot bot commented Nov 13, 2024

Review Checklist

Hello reviewers! 👋 Please follow this checklist when reviewing this Pull Request.

General

  • Ensure that the Pull Request has a descriptive title.
  • Ensure there is a link to an issue (except for internal cleanup and flaky test fixes), new features should have an RFC that documents use cases and test cases.

Tests

  • Bug fixes should have at least one unit or end-to-end test, enhancement and new features should have a sufficient number of tests.

Documentation

  • Apply the release notes (needs details) label if users need to know about this change.
  • New features should be documented.
  • There should be some code comments as to why things are implemented the way they are.
  • There should be a comment at the top of each new or modified test to explain what the test does.

New flags

  • Is this flag really necessary?
  • Flag names must be clear and intuitive, use dashes (-), and have a clear help text.

If a workflow is added or modified:

  • Each item in Jobs should be named in order to mark it as required.
  • If the workflow needs to be marked as required, the maintainer team must be notified.

Backward compatibility

  • Protobuf changes should be wire-compatible.
  • Changes to _vt tables and RPCs need to be backward compatible.
  • RPC changes should be compatible with vitess-operator
  • If a flag is removed, then it should also be removed from vitess-operator and arewefastyet, if used there.
  • vtctl command output order should be stable and awk-able.

@vitess-bot vitess-bot bot added NeedsBackportReason If backport labels have been applied to a PR, a justification is required NeedsDescriptionUpdate The description is not clear or comprehensive enough, and needs work NeedsIssue A linked issue is missing for this Pull Request NeedsWebsiteDocsUpdate What it says labels Nov 13, 2024
@github-actions github-actions bot added this to the v22.0.0 milestone Nov 13, 2024
@mattlord mattlord added NeedsWebsiteDocsUpdate What it says and removed NeedsDescriptionUpdate The description is not clear or comprehensive enough, and needs work NeedsWebsiteDocsUpdate What it says NeedsIssue A linked issue is missing for this Pull Request NeedsBackportReason If backport labels have been applied to a PR, a justification is required labels Nov 13, 2024
Signed-off-by: Matt Lord <[email protected]>
@mattlord mattlord changed the title Binlog: Make ZstdInMemoryDecompressorMaxSize configurable Binlog: Make zstdInMemoryDecompressorMaxSize configurable Nov 13, 2024
@mattlord mattlord changed the title Binlog: Make zstdInMemoryDecompressorMaxSize configurable Binlog: Make ZstdInMemoryDecompressorMaxSize configurable Nov 13, 2024
Copy link

codecov bot commented Nov 13, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 67.41%. Comparing base (f6067e0) to head (623813d).
Report is 4 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #17220      +/-   ##
==========================================
+ Coverage   67.40%   67.41%   +0.01%     
==========================================
  Files        1570     1570              
  Lines      252903   252917      +14     
==========================================
+ Hits       170460   170501      +41     
+ Misses      82443    82416      -27     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

mattlord added a commit to vitessio/website that referenced this pull request Nov 13, 2024
@mattlord mattlord removed the NeedsWebsiteDocsUpdate What it says label Nov 13, 2024
mattlord added a commit to vitessio/website that referenced this pull request Nov 13, 2024
mattlord added a commit to vitessio/website that referenced this pull request Nov 13, 2024
mattlord added a commit to vitessio/website that referenced this pull request Nov 13, 2024
mattlord added a commit to vitessio/website that referenced this pull request Nov 13, 2024
mattlord added a commit to vitessio/website that referenced this pull request Nov 13, 2024
…essed events larger than that

Moving to zstd.NewReader(nil, zstd.WithDecoderLowmem(true), zstd.WithDecoderConcurrency(1))
allows us to process the payload using the least amount of memory possible.

Signed-off-by: Matt Lord <[email protected]>
@mattlord mattlord added the Backport to: release-21.0 Needs to be backport to release-21.0 label Nov 13, 2024
Signed-off-by: Matt Lord <[email protected]>
Signed-off-by: Matt Lord <[email protected]>
Signed-off-by: Matt Lord <[email protected]>
The uncompressed size, read from the header, is what dictates
the decompression/decoding method.

Signed-off-by: Matt Lord <[email protected]>
Signed-off-by: Matt Lord <[email protected]>
Signed-off-by: Matt Lord <[email protected]>
@mattlord mattlord changed the title Binlog: Make ZstdInMemoryDecompressorMaxSize configurable Binlog: Improve ZstdInMemoryDecompressorMaxSize management Nov 13, 2024
@@ -94,4 +95,6 @@ func registerFlags(fs *pflag.FlagSet) {
fs.BoolVar(&vreplicationStoreCompressedGTID, "vreplication_store_compressed_gtid", vreplicationStoreCompressedGTID, "Store compressed gtids in the pos column of the sidecar database's vreplication table")

fs.IntVar(&vreplicationParallelInsertWorkers, "vreplication-parallel-insert-workers", vreplicationParallelInsertWorkers, "Number of parallel insertion workers to use during copy phase. Set <= 1 to disable parallelism, or > 1 to enable concurrent insertion during copy phase.")

fs.Uint64Var(&mysql.ZstdInMemoryDecompressorMaxSize, "binlog-in-memory-decompressor-max-size", mysql.ZstdInMemoryDecompressorMaxSize, "This value sets the uncompressed transaction payload size at which we switch from in-memory buffer based decompression to the slower streaming mode.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add validation to the entered value - there have to be some bounds I guess? And first read it into a local variable before assigning it into mysql.ZstdInMemoryDecompressorMaxSize.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bounds are set by the type. If it’s 0 then streaming mode will always be used. If it’s the max then the in-memory buffers will always be used.

Why would we read it into a local variable first?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would we read it into a local variable first?

We'd need to if there was need for boundary checking. But per your comment boundary checking is not requried, so a local variable is not needed.

@mattlord mattlord merged commit 216fd70 into vitessio:main Nov 16, 2024
99 checks passed
@mattlord mattlord deleted the compression_handling_threshold_flag branch November 16, 2024 02:39
vitess-bot pushed a commit that referenced this pull request Nov 16, 2024
mattlord pushed a commit that referenced this pull request Nov 16, 2024
…ment (#17220) (#17241)

Signed-off-by: Matt Lord <[email protected]>
Co-authored-by: vitess-bot[bot] <108069721+vitess-bot[bot]@users.noreply.github.com>
mattlord added a commit to vitessio/website that referenced this pull request Nov 17, 2024
rvrangel pushed a commit to rvrangel/vitess that referenced this pull request Nov 21, 2024
rvrangel pushed a commit to rvrangel/vitess that referenced this pull request Nov 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Backport to: release-21.0 Needs to be backport to release-21.0 Component: VReplication Type: Enhancement Logical improvement (somewhere between a bug and feature)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature Request: Introduce VTTablet flag to control zstdInMemoryDecompressorMaxSize
3 participants