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

go/vt/mysqlctl: add configurable read buffer to builtin backups #12073

Merged
merged 8 commits into from
Feb 9, 2023

Conversation

maxenglander
Copy link
Collaborator

@maxenglander maxenglander commented Jan 11, 2023

Description

The builtin backup engine reads files from disk, optionally compresses them, and sends them to backupstorage.

Currently, the backup engine uses the *os.File returned by os.Open to read files from disk.

if fd, err = os.Open(name); err != nil {

It then passes this to io.Copy.

_, err = io.Copy(writer, br)

io.Copy reads in blocks of 32*1024 bytes

This is not optimal in all environments. In some environments, it's better to read bigger blocks less frequently.

Changes

This PR:

  • Adds support for read-buffering.
  • Makes both read and write buffering configurable via flags.
  • Decouples the write buffer sizes for writing-files-to-disk-during-restore vs. writing-to-backupstorage-during-backups.

Evidence

Coming up with a benchmark to prove that this is useful is difficult, but anecdotally I've seen a modest performance improvement from increasing the size of the read buffer. I'm not sure if the performance improvement is coming from using the hardware more effectively, or if there are more subtle interactions happening between all the moving pieces of mysqlctl.Backup.

My test environment looks like this:

  • Shard with a single ~37 GiB table (mostly UUIDs).
  • Run vtbackup on...
  • An AWS r5a.xlarge (4 vcpu, 32 GiB mem).
  • With an EBS GP3 provisioned with 6K IOPS and 250 MiB/s throughput.
  • In a container, with 24 GiB mem limit, no CPU limit.
  • Backupstorage is a customized version of s3backupstorage that does some extra stuff.
  • Using compression-engine=external, external-compressor="zstd -c -T4 -1".

Running vtbackup, the baseline backup time is ~215s.
When I add a read buffer of 2MiB, that goes down to ~175s (~18% improvement).

If we feel it's needed, I can try to put together more complete & reproducible evidence.

Related Issue(s)

Fixes #12069

Checklist

Deployment Notes

@vitess-bot
Copy link
Contributor

vitess-bot bot commented Jan 11, 2023

Review Checklist

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

General

  • Ensure that the Pull Request has a descriptive title.
  • If this is a change that users need to know about, please apply the release notes (needs details) label so that merging is blocked unless the summary release notes document is included.
  • If a test is added or modified, there should be a documentation on top of the test to explain what the expected behavior is what the test does.

If a new flag is being introduced:

  • Is it really necessary to add this flag?
  • Flag names should be clear and intuitive (as far as possible)
  • Help text should be descriptive.
  • Flag names should use dashes (-) as word separators rather than underscores (_).

If a workflow is added or modified:

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

Bug fixes

  • There should be at least one unit or end-to-end test.
  • The Pull Request description should include a link to an issue that describes the bug.

Non-trivial changes

  • There should be some code comments as to why things are implemented the way they are.

New/Existing features

  • Should be documented, either by modifying the existing documentation or creating new documentation.
  • New features should have a link to a feature request issue or an RFC that documents the use cases, corner cases and test cases.

Backward compatibility

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

@maxenglander maxenglander force-pushed the maxeng-compress-read-buf branch from 1b9d15d to 7f53b0a Compare January 11, 2023 06:06
@maxenglander maxenglander force-pushed the maxeng-compress-read-buf branch from 7f53b0a to 1abc241 Compare January 11, 2023 06:32
@@ -63,6 +62,16 @@ var (
BuiltinBackupMysqldTimeout = 10 * time.Minute

builtinBackupProgress = 5 * time.Second

// Controls the size of blocks read from disk during backups.
builtinBackupFileReadBufferSize = 0
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Set to zero so that this is opt-in. When set to zero the Golang hard-coded buffer size of 32*1024 is used.


// Controls the byte block size of writes to backupstorage during backups.
// The backupstorage may be a physical file, network, or something else.
builtinBackupStorageWriteBufferSize = 2 * 1024 * 1024 /* 2 MiB */
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The current behavior is that we use the same 2 MiB buffer when writing files to disk during restores or writing to backupstorage during backups.

Backupstorage may or may not go directly to disk, so I think it makes sense to decouple these buffers to they can be tuned independently.

I think it would be even better if builtinbackup didn't do any buffering when reading to or writing from backupstorage, and instead would be better to let each backupstorage engine decide how to handle read/write buffering, maybe with tunable flags.

@maxenglander maxenglander added Type: Enhancement Logical improvement (somewhere between a bug and feature) Component: Backup and Restore labels Jan 11, 2023
@maxenglander maxenglander marked this pull request as ready for review January 11, 2023 19:04
@rsajwani
Copy link
Contributor

Changes look good to me .. Few observations

  • we need to update release notes with this change
  • we need to update website with this change
  • I am ok with this change. We are adding metrics for backup and restore time. Is it possible if we deploy that change first collect data for a week or so and then add this change. This will help us gauge if the values are helping us or not.

@@ -128,6 +137,8 @@ func init() {
func registerBuiltinBackupEngineFlags(fs *pflag.FlagSet) {
fs.DurationVar(&BuiltinBackupMysqldTimeout, "builtinbackup_mysqld_timeout", BuiltinBackupMysqldTimeout, "how long to wait for mysqld to shutdown at the start of the backup.")
fs.DurationVar(&builtinBackupProgress, "builtinbackup_progress", builtinBackupProgress, "how often to send progress updates when backing up large files.")
fs.IntVar(&builtinBackupFileReadBufferSize, "builtinbackup-file-read-buffer-size", builtinBackupFileReadBufferSize, "read files from disk in blocks of this many bytes. Golang defaults are used when set to 0.")
Copy link
Contributor

Choose a reason for hiding this comment

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

minor: should we make it UintVar instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done!

Copy link
Contributor

Choose a reason for hiding this comment

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

I think you need to generate help text again ... Rest looks good

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Doh, fixed

Signed-off-by: Max Englander <[email protected]>
…ltinbackup-file-write-buffer-size

Signed-off-by: Max Englander <[email protected]>
Signed-off-by: Max Englander <[email protected]>
@maxenglander
Copy link
Collaborator Author

maxenglander commented Jan 27, 2023

Is it possible if we deploy that change first collect data for a week or so and then add this change. This will help us gauge if the values are helping us or not.

That's definitely possible. This PR does not change current behavior, so in my opinion it would be fine to merge this first, but wait until after metrics PR is in prod before turning on these flags in prod. I leave it to you to decide :)

@maxenglander maxenglander requested a review from rsajwani January 27, 2023 03:49
Signed-off-by: Max Englander <[email protected]>
Signed-off-by: Max Englander <[email protected]>
@rsajwani
Copy link
Contributor

rsajwani commented Feb 6, 2023

Looks good to me .. there is failure in vreplication_across_db_versions, which is because of #12253.

doc/releasenotes/17_0_0_summary.md Outdated Show resolved Hide resolved
@@ -66,6 +66,7 @@ var (

const (
streamModeTar = "tar"
writerBufferSize = 2 * 1024 * 1024 /*2 MiB*/
Copy link
Member

Choose a reason for hiding this comment

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

why was this moved from builtin to this file? It's not actually used by xtrabackupengine AFAICT.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It is used!

buffer := bufio.NewWriterSize(file, writerBufferSize)

Copy link
Member

Choose a reason for hiding this comment

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

ah it was already being used. And it is no longer used in builtin. 👍

maxenglander and others added 2 commits February 8, 2023 14:43
Co-authored-by: Deepthi Sigireddi <[email protected]>
Signed-off-by: Max Englander <[email protected]>
Signed-off-by: Max Englander <[email protected]>
Comment on lines 9 to 10
--builtinbackup-file-read-buffer-size uint read files from disk in blocks of this many bytes. Golang defaults are used when set to 0.
--builtinbackup-file-write-buffer-size uint write files to disk in blocks of this many bytes. (default 2097152)
Copy link
Contributor

Choose a reason for hiding this comment

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

These have nothing to do with block device block sizes, right? If so, IMO it would be a little more clear to say chunks instead of blocks in this context. Or it may be even more clear/precise to say that we use a buffer of this size each time that we read/write backup data from disk?

@mattlord mattlord merged commit b22b419 into vitessio:main Feb 9, 2023
@mattlord mattlord deleted the maxeng-compress-read-buf branch February 9, 2023 18:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component: Backup and Restore Type: Enhancement Logical improvement (somewhere between a bug and feature)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

builtin backup engine does not do any read buffering when reading from disk
4 participants