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

Support for ZREP_RESUME=yes when using ZREP_R=-R #141

Open
darkpixel opened this issue Nov 29, 2019 · 11 comments
Open

Support for ZREP_RESUME=yes when using ZREP_R=-R #141

darkpixel opened this issue Nov 29, 2019 · 11 comments

Comments

@darkpixel
Copy link

Related to #55 .

The resume feature works beautifully for me in all but one case.

Imagine you have a filesystem:

tank
tank/virt
tank/virt/disk-1
tank/virt/disk-2
tank/virt/disk-3

I want to ensure anything under tank/virt gets a simultaneous snapshot (so all the disks are consistent) and gets backed up.

To accomplish that I run:
ZREP_SEND_FLAGS="--raw -v" ZREP_RESUME=yes ZREP_R=-R ZREP_INC_FLAG=-i /usr/local/bin/zrep -t zrep-remote init tank/virt --redacted-- tank/backups/uslaysd/virt

This snapshots everything under tank/virt and starts sending it off-site.
If the transfer gets interrupted and I attempt to restart it:

root@uslaysdnas01:~# ZREP_SEND_FLAGS="--raw -v" ZREP_RESUME=yes ZREP_R=-R ZREP_INC_FLAG=-i /usr/local/bin/zrep -t zrep-remote init tank/virt --redacted-- tank/backups/uslaysd/virt
tank/virt is at least partially configured by zrep
Error: Partial init of detected but no resume token found. Suggest you zrep clear and start again
root@uslaysdnas01:~# 

If I had to guess, this occurs because zrep is looking at the remote box for tank/virt and it has already been transferred.

The transfer left off at disk-2:
tank/backups/uslaysd/virt/disk-2 1-176c55bc6e-148-78<snip remainder of resume token>

I think this presents a challenge for zrep as it would have to walk through the descendants on the remote system and figure out:

  • What has been successfully transferred
  • What has been partially transferred
  • What hasn't been transferred

I currently have to manually resume from this and it's a complex process.
The first step is to find the name and resume token and then
zfs send -vt <token> | ssh root@--redacted-- zfs receive -sv tank/backups/uslaysd/virt/disk-2.

Once that particular disk is done, I have to look at what the remote has:
zfs list -r tank/backups/uslaysd/virt

Let's say is has disk-1 and disk-2, but it doesn't have disk-3.
Now I have to 'normal' transfer of disk-3:
zfs send -vR tank/virt/disk-3@zrep-remote_000000 | ssh root@--redacted-- zfs receive -sv tank/backups/uslaysd/virt/disk-3

Once that completes, I should have a complete copy of tank/virt@zrep-remote_000000 on the backup box.

This last part I'm a bit fuzzy on--I think if I run a sync, it'll error out. I think I have to run a zrep sentsync tank/virt@zrep-remote_000000 first to make sure both sides agree on what they have and then a sync will work. I need to do more testing to have a definitive answer on that one.

It basically kinda sucks that ZFS treats a zfs send -R tank/virt@zrep-remote_000000 | zfs receive -s tank/backups/uslaysd/virt as a bunch of individual units when handling a resume instead of having maybe a -R flag that can be passed with zfs send -vt to include missing child datasets. It makes things more complex for zrep. :)

@ppbrown
Copy link
Member

ppbrown commented Nov 29, 2019

this is a very long write up.
Which I thank you for.. but I dont want to spend mental cycles processing it, if it isnt neccesary. :)
Please double check with latest git change and see if it still breaks for you :) I think it might be fixed. Let me know.

@darkpixel
Copy link
Author

I'll go check out the diffs and get it deployed to our test servers this evening.

@darkpixel
Copy link
Author

I tested by having a Comcast 'glitch' in the middle of sending tank/virt

When I connected back in and ran sync all it failed because tank/virt/vm-101-disk-1 partially sent. There is a resume token for it sitting on the remote box.

root@usrbgofnas01:~# ZREP_SEND_FLAGS="--raw" ZREP_OUTFILTER="pv -eIrab" ZREP_RESUME=yes ZREP_R=-R ZREP_INC_FLAG=-i /usr/local/bin/zrep -t zrep-remote sync all
sending tank/officeshare@zrep-remote_000004 to uswuxsdrtr01.--redacted--:tank/backups/usrbgof/officeshare
 106KiB [48.8KiB/s] [48.8KiB/s] 
Expiring zrep snaps on tank/officeshare
Also running expire on uswuxsdrtr01.--redacted--:tank/backups/usrbgof/officeshare now...
Expiring zrep snaps on tank/backups/usrbgof/officeshare
sending tank/users@zrep-remote_000003 to uswuxsdrtr01.--redacted--:tank/backups/usrbgof/users
 100KiB [52.4KiB/s] [52.4KiB/s] 
Expiring zrep snaps on tank/users
Also running expire on uswuxsdrtr01.--redacted--:tank/backups/usrbgof/users now...
Expiring zrep snaps on tank/backups/usrbgof/users
sending tank/virt@zrep-remote_000003 to uswuxsdrtr01.--redacted--:tank/backups/usrbgof/virt
cannot receive incremental stream: destination tank/backups/usrbgof/virt/vm-101-disk-1 contains partially-complete state from "zfs receive -s".
3.40MiB [0.00 B/s] [43.5KiB/s]  

@ppbrown
Copy link
Member

ppbrown commented Dec 10, 2019 via email

@darkpixel
Copy link
Author

Unfortnately I think the only way to resolve this is to walk through the child datasets and check if each one has been partially sent (maybe check the destination for a resume token?) and finish up the send.

Say the destination has
tank/virt@zrep_000002
tank/virt/disk1@zrep_000002
tank/virt/disk2@zrep_000001 (but a partial send of zrep_000002)
tank/virt/disk3@zrep_000001 (zrep_000002 never got sent because of an earlier problem during the send of disk2)

Maybe a sync all creates a new snapshot like zrep_000003, and then figures out what each child needs
tank/virt needs zrep_000003 from zrep_000002
tank/virt/disk1 needs zrep_000003 from zrep_000002
tank/virt/disk2 needs to get the resume token, finish the send of zrep_000002, then send zrep_000003 from zrep_000002
tank/virt/disk3 needs zrep_000003 from zrep_000001 (or maybe zrep_000002 needs to be sent first?)

@ppbrown
Copy link
Member

ppbrown commented Jan 13, 2020 via email

@darkpixel
Copy link
Author

The more I think about this, the more annoying it is....

zfs snapshot -r tank/virt@mysnap is great for making sure all disks attached to a VM are snapshotted at the exact same moment....but zfs send -Ri @some-other-snap tank/virt@mysnap is a terrible way to ensure all the child datasets and volumes get transferred.

Last time I checked, zfs send -R will barf if you create a new zvol or dataset underneath...because the newly created dataset has no @some-other-snap and it has no existing data on the destination host...meaning it needs a zfs send -R tank/virt/new-disk@mysnap or a zfs send tank/virt/new-disk@mysnap just to make it consistent with the rest of the filesystem.

I wonder if the ZFS devs are working on a solution to this, or if they feel it's up to individual admins / software devs to work around it...

@ppbrown
Copy link
Member

ppbrown commented Jan 13, 2020 via email

@darkpixel
Copy link
Author

If it bails out, it would make it impossible to simultaneously snapshot the underlying filesystems for backup unless an external tool was used.

I think the current behavior is acceptable--you'll get an error from ZFS and it will fail to sync.

I'm debating writing a quick script to compare both the source and destination filesystems to figure out where things left off and manually bring them back into sync....sort of like a 'zrep fixup' for when an outage causes this...

As for -R, I technically transfer all my datasets that way--even if they don't have children.

I do that because when you run a sync all there's no knob on the filesystem to indicate you want it transferred with -R, just the environment variable. Out of ~6 datasets I back up every night, only one of them has children.

The current workflow when there are no children or you aren't using -R as I understand it is basically:

  1. Taking a snapshot of the local filesystem
  2. Looking at the remote filesystem for a resume token
  3. Resuming if necessary
  4. Doing the transfer from the last zrep snapshot to the current zrep snapshot

Maybe adjust it to:

  1. Take a snapshot of the local filesystem
  2. Gather a list of child datasets (zfs list -r -o name tank/virt) from the local system
  3. Gather a list of child datasets from the remote system
  4. For each remote child dataset, look for a resume token
  5. For each resume token found, handle the resume.

If no resume tokens were found, just zfs send -R tank/virt@zrep-latest-snapshot and you're done.
If tokens were found, then...you have a dataset in a semi-consistent state. You may still have child datasets that don't exist on the remote (in case of a failed init) or exist at an older snapshot (in case of an earlier failed sync)

  1. Identify remote child datasets that don't have the current @zrep-latest-snapshot. Figure out what they do have in common (i.e. @zrep-previous-snapshot) and sync them.

That should bring everything into sync with one minor exception that I think is probably fine. If you delete a child dataset on the source server, it will exist forever on the destination server since it's not involved in syncing. I think it's probably a good idea to not have zrep delete datasets and just stick to snapshots.

@ppbrown
Copy link
Member

ppbrown commented Jan 14, 2020 via email

@ppbrown
Copy link
Member

ppbrown commented Jan 14, 2020 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants