# 拷贝文件

  • 在本机上拷贝文件时:
    • 通常使用 cp 命令。
    • 跨磁盘拷贝文件时,两个磁盘分别承受读、写负载。在同一磁盘拷贝文件时,读、写负载同时作用于该磁盘,拷贝速度慢很多,不如创建硬链接。
  • 跨主机拷贝文件时:
    • 通常使用 scp、rsync 命令。
    • 跨主机拷贝文件时,磁盘 IO 速度可能比网络 IO 速度快多倍,比如 100MB/s 对 10MB/s 。建议先制作文件的压缩包,拷贝到目标主机之后再解压,使得总耗时更少,只是压缩、解压需要占用一些时间和 CPU 。
    • 拷贝大量小文件时,也建议制作压缩包。因为每个文件都需要拷贝一次文件元数据,增加了耗时。

# cp

cp <src_path> <dst_path>  # 将文件从源路径拷贝到目标路径
    -a       # 相当于-dpr
    -d       # 若源文件为 link file ,则复制 link file 的属性(而非文件本身)
    -p       # 将源文件的权限、属性也拷贝过去(否则会使用默认属性)
    -r       # 递归操作(用于复制目录)

    -f       # 若目标文件已存在,则删除它再尝试拷贝
    -i       # 若目标文件已存在,则提示用户是否进行覆盖
    -n       # 若目标文件已存在,则不覆盖
    -u       # --update ,当目标文件不存在,或源文件比目标文件更新时,才执行拷贝
    -v       # 显示执行过程的详细信息
  • Linux 发行版一般设置了 alias cp='cp -i' ,所以 -f 选项无效。
  • 例:
    cp f1 f2
    cp f1 f2 /tmp
    cp -r *  /tmp   # 源路径中包含通配符 * 时,不会拷贝隐藏文件
    cp -r .  /tmp
    cp -a *  /tmp
    
  • 执行 cp f1 f2 时:
    • 如果 f2 不存在,则会先创建一个空的 f2 文件,再将 f1 的内容拷贝过去。
    • 如果 f2 已存在,则会先将 f2 的内容清空,再将 f1 的内容拷贝过去,因此目标文件依然使用 f2 的 inode 号。
      • 如果该过程中有其它进程也在修改 f2 ,则会导致 cp 出错。

# ln

:用于创建文件的链接,并不会实际拷贝文件。

  • 命令:
    ln <src_path> <dst_path>  # 创建文件的硬链接
        -s    # 创建文件的软链接
        -f    # 若目标文件已存在,则覆盖它
    
    • 创建链接时,源路径、目标路径都必须是绝对路径。
    • 不支持给目录创建硬链接,不支持跨磁盘分区创建硬链接。
    • 可以给目录创建软链接,可以跨磁盘分区创建软链接。
  • 例:
    [root@CentOS ~]# ln -s /tmp tmp
    [root@CentOS ~]# ls -lh
    total 0
    lrwxrwxrwx 1 root root 4 Jan  8 14:21 tmp -> /tmp
    [root@CentOS ~]# rm -f tmp/       # 如果软链接文件指向一个目录,删除时不能加上 / 后缀,否则会被视作删除目标目录
    rm: cannot remove ‘tmp/’: Is a directory
    [root@CentOS ~]# rm -f tmp
    

# dd

:用于在本机上拷贝文件,还支持转换文件格式。不支持拷贝目录。

  • 命令:
    dd
        if=<file>          # 源文件,默认为 stdin
        of=<file>          # 目标文件,默认为 stdout
    
        count=<blocks>     # 拷贝多少个块(默认为拷贝全部数据)
        bs=<bytes>         # 读写数据时,内存缓冲区的大小。默认为 512 。取值过小会减慢速度,取值过大会占用大量内存
        ibs=<bytes>        # 每次读取多少字节的数据,默认为 512
        obs=<bytes>        # 每次写入多少字节的数据,默认为 512
    
    • dd 拷贝文件时,会以 ibs 为单位读取数据,放入内存缓冲区 bs ,然后以 obs 为单位写入目标文件。
  • 例:
    dd if=/dev/sda1 of=/dev/sda2    # 从 if 设备拷贝数据到 of 设备
    dd if=/dev/cdrom of=cd.iso      # 拷贝文件并转换成 iso 文件
    
  • 例:
    [root@CentOS ~]# dd if=/dev/urandom of=f1 bs=1M count=1024    # 拷贝生成一个指定大小、随机内容的文件
    1024+0 records in
    1024+0 records out
    1073741824 bytes (1.1 GB) copied, 74.6221 s, 14.4 MB/s
    [root@CentOS ~]# dd if=f1 of=f2 bs=1M                         # 拷贝文件,这也能测试磁盘的顺序读写速度
    1024+0 records in
    1024+0 records out
    1073741824 bytes (1.1 GB) copied, 7.92427 s, 136 MB/s
    

# scp

:安全拷贝协议(Secure copy protocol),用于在主机之间拷贝文件,基于 SSH 协议加密通信。

  • 命令:
    scp
        <file>... [email protected]:/root  # 将本机的文件拷贝到其它主机(需要通过 SSH 认证)
        [email protected]:/root/f1 /root   # 将其它主机的文件拷贝到本机的指定目录
        -C      # 传输数据流时启用压缩
        -P 22   # 指定 SSH 的端口
        -r      # 递归操作(用于拷贝目录)
    

# rsync

:用于在本机拷贝文件、目录,或跨主机拷贝。

  • 与 scp 相比:
    • rsync 将每个文件分成多个文件块传输,如果目标文件中已包含 md5 值相同的块,则不拷贝。因此支持断点续传、增量拷贝。
    • rsync 跨主机拷贝时,需要源主机、目标主机都安装了 rsync 。
  • 命令:
    rsync
          SRC... DEST             # 在本机拷贝文件(此时相当于 cp 命令)
          SRC... [USER@]HOST:DEST # 将本机的文件拷贝到其它主机
          [USER@]HOST:SRC... DEST # 将其它主机的文件拷贝到本机
          -e "ssh -p 1022"        # 修改 SSH 协议的配置参数
          -z                      # 传输数据流时启用压缩(不管是本机拷贝,还是跨主机拷贝)
    
          -a                      # 保留文件属性,且递归处理目录
          -P                      # 保留未完全拷贝的文件,并显示传输进度
          -q                      # --quite ,隐藏拷贝过程的信息,除非是报错
    
          --exclude=log/*         # 排除某些文件,不拷贝它们
          --ignore-existing       # 如果目标文件已存在,则不拷贝
          -u                      # --update ,如果目标文件已存在,且修改时间比源文件更新,则不拷贝
          --delete                # 删除目标目录比源目录多出的文件
          --inplace
          --append
    
    • 当 SRC 是目录时,如果以 / 结尾,则相当于 cp SRC/* DEST ,否则相当于 cp SRC DEST/SRC
    • 如果 DEST 目录不存在,则会自动创建。
  • 例:
    rsync -aP /tmp /data
    rsync -aP --inplace -e ssh  /root/f1 10.0.0.1:/root
    
  • rsync 将 src_file 拷贝文件到 dst_file 时:
    • 如果 dst_file 不存在(即目标文件路径未被占用),则从头拷贝 src_file 。
      • 拷贝时,默认先暂存到 DEST 目录下一个临时文件。比如拷贝 f1 文件时会暂存为 .f1.GRds8g 文件,等拷贝完才将它重命名为 f1 。如果拷贝中断,则删除该文件。
      • 启用 -P 选项时,即使未完全拷贝文件,rsync 就中断,也会将临时文件重命名为 dst_file 。此时该文件是不完整的, modify time 为 1970-01-01 。
    • 如果 dst_file 已存在,则检查其 md5 值、文件属性是否与 src_file 一致。
      • 如果相同,则不拷贝该文件。
      • 如果不同,则默认会从头拷贝 src_file 。
        • 例如事先用 cp 命令等其它方式拷贝该文件,即使已经拷贝完,也会因为文件的 modify time 与 src_file 不一致,导致 rsync 从头拷贝该文件。
        • 以下情况不会创建临时文件,而是直接保存到 dst_file 。
          • 启用 --inplace 选项时,会检查 dst_file 中各个文件块的 md5 值,如果与 src_file 不同,则拷贝该文件块。如果文件属性不同,则单独拷贝文件属性。
          • 启用 --append 选项时,会检查 dst_file 的长度,如果比 src_file 短,则拷贝缺少的字节到 dst_file 的末尾。因此不保证 dst_file 与 src_file 的长度、内容、文件属性一致。
        • 综上,如果想实现断点续传,避免从头拷贝文件,建议启用 -P 和 --inplace 选项。

# 数据备份

  • 按备份层级的不同,可将备份方式分为:

    • 物理备份
      • :将一块磁盘的数据,备份到另一块磁盘中,以 block 为单位拷贝数据。
      • 优点:
        • 拷贝、恢复的速度很快,接近磁盘的读写速度上限。
      • 缺点:
        • 磁盘中有些数据可能不需要备份,也会被拷贝,导致备份包占用更多磁盘空间。
    • 逻辑备份
      • :将一个文件的数据,备份到另一个文件中,以 byte 为单位拷贝数据。
  • 备份数据存在一定耗时,在此期间,数据可能被业务进程修改,导致备份出错。因此,存在两种备份方式:

    • 在线备份
      • :又称为热备份,是在备份期间,继续运行业务进程,对用户无影响。
    • 离线备份
      • :又称为冷备份,是在备份期间,停止运行业务进程,不为用户提供服务。
  • 假设需要备份一个文件或目录,每天备份一次,生成一个压缩包,最多保留 30 个压缩包。存在几种备份方式:

    • 全量备份
      • :每天备份一次,每次将所有文件都备份。
      • 优点:
        • 备份速度最慢。每次备份,都需要读取所有文件。
      • 缺点:
        • 恢复速度最快,只需要解压一个压缩包。
        • 占用的磁盘空间最多。即使待备份的数据从未变化,也需要保留 30 个体积一样大的压缩包。
    • 增量备份
      • :第一个压缩包,采用全量备份。之后每次备份,都是比较当前时刻的数据,与上一个压缩包的差异,然后只备份这些差异。
      • 优点:
        • 备份速度较快。
        • 占用的磁盘空间最少。每次增量备份时,差异越少,生成的压缩包体积越小。
      • 缺点:
        • 恢复速度最慢。如果想恢复到第 N 个增量备份,则需要先解压第一个压缩包,然后按顺序应用各个增量备份,直到第 N 个增量备份。
    • 差异备份
      • :每次备份时,比较当前时刻的数据,与上一次全量备份的差异。因此恢复文件时,只需要使用一个全量备份和一个差异备份。
      • 效果介于全量备份与增量备份之间。
  • 何时采用增量备份?

    • 如果待备份的数据,不超过 100MB ,
      • 可以用 zip 等压缩命令,进行全量备份。
      • 如果这些数据是文本格式,则可以用 git 命令,进行增量备份。
    • 如果待备份的数据,超过 100MB ,则全量备份太浪费磁盘空间,应该采用增量备份、差异备份。
      • 可以用 tar 命令,进行增量备份。不过 tar 命令的功能较少。
      • 可以用 rsnapshot 命令,进行增量备份。
    • 如果待备份的数据,超过 1TB ,则逻辑备份太浪费时间,应该采用物理备份。

# dump

  • dump 命令用于备份数据(属于物理备份、增量备份),只支持 etx2、etx3、etx4 文件系统。

  • 命令:

    dump [option] <path>  # 读取一个路径中的数据,进行备份
          -f <file>       # 保存为指定文件
          -[0-9]          # 设置备份级别
          -j              # 压缩为 bzip2 格式
    
    • path 可以是文件、目录、磁盘分区。只有为磁盘分区时,才支持增量备份。
    • 备份级别有 0~9 十种,0 是全量备份,1~9 都是增量备份。
      • 比如用 0 全量备份一次之后,可用 1 增量备份。下一次备份时,用 2 就是增量备份(级别加一),用 1 就是差异备份(覆盖之前的同级数据)。
    • 即使用 -j 指定了压缩格式,但 dump 生成的备份文件,并不是通用的压缩文件,因为增加了一些备份信息。只能被 restore 命令解压。
    • 例:
      dump -j -0f tmp.bz2 /tmp/
      
  • 命令:

    restore
            -f <file> # 指定备份文件
            -r        # 还原数据(会根据备份文件中的备份信息,将数据还原到原路径)
            -t        # 显示备份文件的内容
            -C        # 比较当前文件与备份文件的差异(比如旧文件被修改、删除,但是增加新文件时不算差异)
    
    • restore 会生成一个 restoresymtable 文件,用于在增量备份时传递信息,可以删除。
    • 例:
      restore -tf tmp.bz2
      

# xfsdump

  • xfs 文件系统,提供了 xfsdump 命令用于备份数据(属于物理备份、增量备份),提供了 xfsrestore 命令用于恢复数据。

# rsnapshot

  • rsnapshot 是一个数据备份工具(属于逻辑备份、增量备份)。

    • 采用 perl 语言开发,适用于类 Unix 系统。
    • 基于 rsync 命令进行工作,可以备份本机的数据,也可以通过 SSH 备份其它主机的数据。
    • 每次备份,会将目标文件拷贝到一个新的 snapshot 目录下。
      • 如果目标文件在之前的 snapshot 目录下也存在,没有变化,则不拷贝该文件,而是创建硬链接,从而减少占用的磁盘空间。
      • 用户不能将 snapshot 目录做成压缩包,否则硬链接失效。建议将需要备份的源文件,做成压缩包,从而减少占用的磁盘空间。
  • 安装:

    yum install rsnapshot
    

用法示例:

  1. 编写一个配置文件 /data/rsnapshot/rsnapshot.conf

    # 配置文件的语法版本
    config_version  1.2
    
    loglevel  2
    logfile   /data/rsnapshot/rsnapshot.log
    lockfile  /data/rsnapshot/rsnapshot.pid
    
    # 将快照保存到哪个目录
    snapshot_root /data/rsnapshot/snapshots/
    
    # 每种类型的快照,最多保留多少个
    # 这些快照,会保存为多个目录,命名格式为 $snapshot_root/$type.$num/ ,例如 /data/rsnapshot/snapshots/hourly.0/
    # 同种类型的快照中,最新一个快照的编号为 0 。每新增一个快照,所有历史快照的编号都会递增 1
    retain  hourly  24
    retain  daily   7
    retain  weekly  4
    retain  monthly 3
    
    # 配置 rsync 命令的可执行文件、参数
    cmd_rsync /usr/bin/rsync
    # rsync_short_args -a
    # rsync_long_args  --delete --numeric-ids --relative --delete-excluded
    # ssh_args -p 22
    # include  ...
    # exclude  ...
    
    # 基于 rsync 命令,拷贝文件,保存到 $snapshot_root/$retain/10.0.0.1/ 目录下
    backup  [email protected]:/tmp   10.0.0.1/
    
    # 执行自定义的 shell 脚本,拷贝数据到 $snapshot_root/$retain/mysql/ 目录下
    # backup_script   /etc/rsnapshot/dump_mysql.sh mysql/
    
    • 配置文件中的分隔符,必须使用 Tab ,不能使用空格。可执行命令 sed -i 's#\x20#\t#g' rsnapshot.conf 进行转换。
  2. 添加 crontab 定时任务,定期执行 rsnapshot 命令:

    0 * * * *   /usr/bin/rsnapshot -c /data/rsnapshot/rsnapshot.conf hourly   # 生成一个 hourly 类型的快照
    0 1 * * *   /usr/bin/rsnapshot -c /data/rsnapshot/rsnapshot.conf daily
    0 1 * * 7   /usr/bin/rsnapshot -c /data/rsnapshot/rsnapshot.conf weekly
    0 1 1 * *   /usr/bin/rsnapshot -c /data/rsnapshot/rsnapshot.conf monthly