数据备份的方法讨论

Linux下的备份方式小结

Posted by wszqkzqk on April 27, 2023
本文字数:3783

本文封面背景图采用CC-BY-SA-4.0协议,来源于Wikipedia

前言

本文主要讨论Linux下的数据备份方式

rsync

rsync是一个远程数据同步工具,可通过sshrsh传输数据,支持匿名传输,速度快,安全性高。

  • 可按文件大小、时间等进行过滤
  • 可使用includeexclude文件进行过滤
  • 可使用--delete参数删除目标端没有的文件
  • 可使用--link-dest参数创建硬链接
  • 可使用--bwlimit参数限制带宽
  • 可使用--progress参数显示进度
  • 可使用--dry-run参数模拟运行
  • 可使用--log-file参数记录日志
  • 可使用--password-file参数指定密码文件
  • 可使用--exclude-from参数指定排除文件
  • 可使用--include-from参数指定包含文件
  • 可使用--files-from参数指定文件列表
  • 可使用--exclude参数排除文件
  • 可使用--include参数包含文件
  • 可使用--max-size参数指定最大文件大小
  • 可使用--min-size参数指定最小文件大小
  • 可使用--max-delete参数指定最大删除文件数
  • 可使用--partial参数保留部分文件
  • 可使用--partial-dir参数指定部分文件目录
  • 可使用--timeout参数指定超时时间
  • 可使用--contimeout参数指定连接超时时间
  • 可使用--daemon参数启动守护进程
  • 可使用--address参数指定守护进程监听地址
  • 可使用--port参数指定守护进程监听端口
  • 可使用--config参数指定配置文件
  • 可使用--blocking-io参数指定阻塞IO
  • 可使用--no-blocking-io参数指定非阻塞IO
  • 可使用--stats参数显示统计信息
  • 可使用--progress参数显示进度
  • 可使用--no-motd参数禁用MOTD
  • 可使用--no-detach参数禁用守护进程
  • 可使用--no-inc-recursive参数

笔者的主要需求是将内容备份到本地的机械硬盘中,所以使用rsync的命令如下:

sudo rsync -aAXHv --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found","/boot/efi/*" "/efi/*"} / /XXX/目标目录 --delete

其中的-aAXHvrsync的常用参数,表示归档模式、保留ACL、保留扩展属性、保留硬链接、显示进度。

由于笔者使用的是btrfs,有时候想要备份单个子卷,可以使用--one-file-system参数或者-x参数,表示不跨越文件系统边界:

sudo rsync -aAXHvx / /XXX/目标目录 --delete

这里的-x参数表示不跨越文件系统边界,这样备份的就只有根目录所在子卷的内容。

tar

tar是一个归档工具,可以将多个文件或目录打包成一个文件,也可以将一个文件解包成多个文件或目录,支持压缩,但是不支持增量备份。tar还支持设置压缩参数,支持不同的压缩算法:

  • z:使用gzip压缩
  • j:使用bzip2压缩
  • J:使用xz压缩
  • --lzma:使用lzma压缩
  • --lzip:使用lzip压缩
  • --lzop:使用lzop压缩
  • --zstd:使用zstd压缩
  • -a:根据文件拓展名自动选择压缩算法

笔者的主要需求是将内容备份到本地的机械硬盘中,所以使用tar的命令如下:

sudo tar -cavpf /XXX/目标目录/backup.tar --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found","/boot/efi/*" "/efi/*"} /

同理,如果想要备份单个子卷,可以使用--one-file-system参数,表示不跨越文件系统边界:

sudo tar -cavpf --one-file-system /XXX/目标目录/backup.tar /

dd和squashfs

dd是一个磁盘拷贝工具,可以将一个磁盘的内容拷贝到另一个磁盘,也可以将一个磁盘的内容拷贝到一个文件,也可以将一个文件拷贝到一个磁盘,也可以将一个文件拷贝到另一个文件,不支持增量备份。dd的优点是可以完整备份整个硬盘设备,缺点是备份的文件很大,会拷贝原有硬盘中没有数据的部分,而且不能压缩,占用较多的空间。因此,笔者一般会推荐在使用dd备份时,使用squashfs压缩,这样可以节省空间。

squashfs是一个只读压缩文件系统,它支持保留Linux权限及xattr拓展权限,可以调节块大小,保证随机访问性能,对压缩的支持也非常丰富,可以选择不同的压缩算法及压缩率。在一般场景中,笔者推荐使用zstd:3的压缩算法,这样可以节省空间,而且压缩速度快、CPU占用很小。与tar.zst等基于tar的压缩备份方案相比,squashfs最大的优势在于可以直接挂载使用,而不需要解压缩,这样可以节省大量的时间;另外,squashfs还支持文件级别重复数据删除,进一步节省空间。

文件/目录级备份

如果需要备份已经挂载的文件系统上的文件,可以直接使用mksquashfs,例如:

# 备份 /home 目录
sudo mksquashfs /home /XXX/目标目录/backup.squashfs -comp zstd -Xcompression-level 3 -b 1M
# 备份 / 目录
sudo mksquashfs / /XXX/目标目录/backup.squashfs -comp zstd -Xcompression-level 3 -b 1M -e /dev -e /proc -e /sys -e /tmp -e /run -e /mnt -e /media -e /lost+found -e /boot/efi -e /efi
# 备份 / 子卷
sudo mksquashfs / /XXX/目标目录/backup.squashfs -comp zstd -Xcompression-level 3 -b 1M --one-file-system

这样创建的squashfs是一个直接包含备份文件的文件系统,可以直接挂载使用。

块设备级备份

有时候我们可能需要备份某些在Linux下不方便直接挂载并备份的分区,比如受BitLocker加密的NTFS分区等,这时,为了完成保留整个硬盘设备的信息,我们可以直接备份整个硬盘设备。如果需要备份整个硬盘设备,可以使用ddmksquashfs结合,即,用mksquashfs调用dd的输入流,例如:

sudo mksquashfs - /XXX/目标目录/backup.squashfs -p "backup.img f 0644 root root dd if=/dev/nvme0n1 bs=1M" -p "/ d 0755 0 0" -comp zstd -Xcompression-level 3 -b 1M

这里的-表示标准输入流,-p表示添加文件,-p后面的内容是mksquashfs的文件描述符,f表示类型为文件,后面紧跟的是权限信息,dd if=/dev/nvme0n1 bs=1M表示调用dd的输入流,if=/dev/nvme0n1表示输入文件,bs=1M表示块大小;/表示根目录,d表示类型为目录,后面同样跟有权限信息。

整体上,这个命令的意思是,将/dev/nvme0n1的内容作为输入流,作为backup.img文件的内容,将backup.img文件放在创建的squashfs文件系统的根目录,然后压缩成squashfs文件系统。这样既保留了整个硬盘的完整存储信息,又启用压缩,节省了空间。不过,从这样的备份中读取内容时,需要先挂载squashfs文件系统,然后加载其中的backup.img文件为loop设备,再挂载所需要挂载的分区。

btrfs send

由于笔者使用的是btrfs,除了以上较为通用的方法外,还可以使用btrfs的sendreceive命令进行增量备份。send命令可以将一个子卷的内容发送到一个文件中,receive命令可以将一个文件中的内容接收到一个子卷中。send命令支持增量备份,可以将两个子卷之间的差异部分发送到一个文件中,receive命令也支持增量备份,可以将一个文件中的差异部分接收到一个子卷中。

btrfs send只能发送只读的btrfs子卷,我们需要首先创建当前子卷的只读快照,例如:

sudo btrfs subvolume snapshot -r / /XXX/snapshots/@-ro

然后即可使用btrfs send命令将快照发送到另一个btrfs文件系统中,例如:

sudo btrfs send /XXX/snapshots/@-ro | sudo btrfs receive /XXX/目标目录

增量备份与之类似,只需要在send命令中添加-p参数,例如:

sudo btrfs send -p /XXX/snapshots/@-ro /XXX/snapshots/@-ro-new | sudo btrfs receive /XXX/目标目录

btrfs receive所新建的子卷也是只读的,如果需要使用,需要对其创建可读写的快照,例如:

sudo btrfs subvolume snapshot /XXX/目标目录/@-ro /XXX/目标目录/@-rw