【问题标题】:Speed up rsync with Simultaneous/Concurrent File Transfers?通过同时/并发文件传输加速 rsync?
【发布时间】:2014-07-26 08:23:02
【问题描述】:

我们需要尽快将15TB 的数据从一台服务器传输到另一台服务器。我们目前正在使用rsync,但是当我们的网络能够达到900+Mb/s(使用iperf 测试)时,我们只能获得大约150Mb/s 的速度。我已经对磁盘、网络等进行了测试,并认为只是 rsync 一次只传输一个文件导致速度变慢。

我找到了一个脚本,可以为目录树中的每个文件夹运行不同的 rsync(允许您限制 x 个数),但我无法让它工作,它仍然一次只运行一个 rsync。

我找到了script here(复制如下)。

我们的目录树是这样的:

/main
   - /files
      - /1
         - 343
            - 123.wav
            - 76.wav
         - 772
            - 122.wav
         - 55
            - 555.wav
            - 324.wav
            - 1209.wav
         - 43
            - 999.wav
            - 111.wav
            - 222.wav
      - /2
         - 346
            - 9993.wav
         - 4242
            - 827.wav
      - /3
         - 2545
            - 76.wav
            - 199.wav
            - 183.wav
         - 23
            - 33.wav
            - 876.wav
         - 4256
            - 998.wav
            - 1665.wav
            - 332.wav
            - 112.wav
            - 5584.wav

所以我希望为 /main/files 中的每个目录创建一个 rsync,一次最多可以创建 5 个。所以在这种情况下,将运行 3 个 rsync,分别用于 /main/files/1/main/files/2/main/files/3

我这样尝试过,但它一次只为 /main/files/2 文件夹运行 1 个 rsync:

#!/bin/bash

# Define source, target, maxdepth and cd to source
source="/main/files"
target="/main/filesTest"
depth=1
cd "${source}"

# Set the maximum number of concurrent rsync threads
maxthreads=5
# How long to wait before checking the number of rsync threads again
sleeptime=5

# Find all folders in the source directory within the maxdepth level
find . -maxdepth ${depth} -type d | while read dir
do
    # Make sure to ignore the parent folder
    if [ `echo "${dir}" | awk -F'/' '{print NF}'` -gt ${depth} ]
    then
        # Strip leading dot slash
        subfolder=$(echo "${dir}" | sed 's@^\./@@g')
        if [ ! -d "${target}/${subfolder}" ]
        then
            # Create destination folder and set ownership and permissions to match source
            mkdir -p "${target}/${subfolder}"
            chown --reference="${source}/${subfolder}" "${target}/${subfolder}"
            chmod --reference="${source}/${subfolder}" "${target}/${subfolder}"
        fi
        # Make sure the number of rsync threads running is below the threshold
        while [ `ps -ef | grep -c [r]sync` -gt ${maxthreads} ]
        do
            echo "Sleeping ${sleeptime} seconds"
            sleep ${sleeptime}
        done
        # Run rsync in background for the current subfolder and move one to the next one
        nohup rsync -a "${source}/${subfolder}/" "${target}/${subfolder}/" </dev/null >/dev/null 2>&1 &
    fi
done

# Find all files above the maxdepth level and rsync them as well
find . -maxdepth ${depth} -type f -print0 | rsync -a --files-from=- --from0 ./ "${target}/"

【问题讨论】:

    标签: bash shell ubuntu-12.04 rsync simultaneous


    【解决方案1】:

    我发现 UDR/UDT 是一个了不起的工具。 TLDR;它是 rsync 的 UDT 包装器,利用多个 UPD 连接而不是单个 TCP 连接。

    参考:https://udt.sourceforge.io/ & https://github.com/jaystevens/UDR#udr

    如果您使用任何 RHEL 发行版,他们已经为您预编译了...http://hgdownload.soe.ucsc.edu/admin/udr

    我遇到的唯一缺点是您不能指定不同的 SSH 端口,因此您的远程服务器必须使用 22。

    不管怎样,安装完 rpm 之后,就这么简单:

    udr rsync -aP user@IpOrFqdn:/source/files/* /dest/folder/
    

    在大多数情况下,您的传输速度会大幅提高,具体取决于服务器,我发现传输速度可以轻松提高 10 倍。

    旁注:如果您选择先对所有内容进行 gzip,请确保使用 --rsyncable arg 以便它只更新已更改的内容。

    【讨论】:

      【解决方案2】:

      我找到的最短版本是使用parallel--cat 选项,如下所示。这个版本避免使用xargs,只依赖parallel的特性:

      cat files.txt | \
        parallel -n 500 --lb --pipe --cat rsync --files-from={} user@remote:/dir /dir -avPi
      
      #### Arg explainer
      # -n 500           :: split input into chunks of 500 entries
      #
      # --cat            :: create a tmp file referenced by {} containing the 500 
      #                     entry content for each process
      #
      # user@remote:/dir :: the root relative to which entries in files.txt are considered
      #
      # /dir             :: local root relative to which files are copied
      

      来自files.txt的示例内容:

      /dir/file-1
      /dir/subdir/file-2
      ....
      

      请注意,这不会使用 -j 50 来计算工作,这在我这里不起作用。相反,我使用-n 500 来计算每个作业的记录数,根据记录总数计算为一个合理的数字。

      【讨论】:

        【解决方案3】:

        您是否尝试过使用rclone.org

        使用rclone,您可以执行类似的操作

        rclone copy "${source}/${subfolder}/" "${target}/${subfolder}/" --progress --multi-thread-streams=N
        

        其中--multi-thread-streams=N 表示您希望生成的线程数。

        【讨论】:

        • 致命错误:未知标志:--multi-thread-streams
        • @StepanYakovenko 我已经测试了这个标志,它在 1.55.1 版本中工作:rclone copy killmouseaccel killmouseaccel2 --multi-thread-streams=4 --progress 2021/06/01 13:50:30 NOTICE: Config file not found - using defaults Transferred: 0 / 0 Bytes, -, 0 Bytes/s, ETA - Transferred: 1 / 1, 100% Elapsed time: 0.0s
        • 与@Han.Oliver 相同:正如我在上一条评论中指出的那样,该标志正在发挥作用
        • 刚刚测试了 rclone,因为该评论及其精彩
        • 最佳选择。只需运行 32 个流,其速度几乎比使用 finder 或 rsync 复制快 50 倍。
        【解决方案4】:

        更新答案(2020 年 1 月)

        xargs 现在是实现并行执行的推荐工具。它几乎无处不在。要运行多个rsync 任务,命令将是:

        ls /srv/mail | xargs -n1 -P4 -I% rsync -Pa % myserver.com:/srv/mail/
        

        这将列出/srv/mail 中的所有文件夹,将它们通过管道传送到xargs,它会一一读取它们并一次运行4 个rsync 进程。 % 字符替换每个命令调用的输入参数。

        使用parallel的原始答案:

        ls /srv/mail | parallel -v -j8 rsync -raz --progress {} myserver.com:/srv/mail/{}
        

        【讨论】:

        • 注意,如果您通过各种方式自定义ls输出,例如LISTFLAGS 变量或DIR_COLORS文件,您可能需要使用ls --indicator-style=none来防止ls追加路径名的符号(例如* 表示可执行文件)。
        • 我发现如果我使用 cd /sourcedir 效果会更好;并行 -j8 -i rsync -aqH {} /destdir/{} -- *
        • @Manuel Riel '{}' 是什么意思?
        • 这不是一个有效的解决方案,如下所示:unix.stackexchange.com/questions/189878/… 此解决方案将为列表中的每个文件创建一个 rsync 调用
        • 这个答案很有帮助!我建议在rsync 之前添加--sshdelay 0.2,以确保您不会使远程服务器上的sshd 过载。
        【解决方案5】:

        我发现最简单的方法是在 shell 中使用后台作业:

        for d in /main/files/*; do
            rsync -a "$d" remote:/main/files/ &
        done
        

        注意它不会限制工作的数量!如果你是网络绑定的,这不是一个真正的问题,但如果你正在等待旋转生锈,这将破坏磁盘。

        你可以添加

        while [ $(jobs | wc -l | xargs) -gt 10 ]; do sleep 1; done
        

        在原始形式的作业控制的循环内。

        【讨论】:

          【解决方案6】:

          网络上列出了许多替代工具和方法来执行此操作。例如:

          • NCSA Blog 描述了使用 xargsfind 来并行化 rsync,而无需为大多数 *nix 系统安装任何新软件。

          • parsync 为并行rsync 提供了一个功能丰富的Perl 包装器。

          【讨论】:

          • 请不要只发布一些工具或库作为答案。至少在答案本身中展示how it solves the problem
          • @i_m_mahii Stack Exchange 应该自动保留链接页面的副本。
          • parsync 很棒
          • 与其他人可能会说的相反,提出一个仅仅是工具的解决方案确实对我们中的一些人有所帮助。 “遵守或离开!”人群显然不只是想帮助别人。因此,代表所有今天刚刚从您的帖子中发现这两个包的人感谢您的帖子,以及那些意识到 xarg 和 find(没有这些包)也可以解决问题的人。发帖并让选民尽自己的一份力量,而忽略那些似乎不时在此处“强制执行”的苦涩“离开我的网站”的家伙。
          • 因为我们中的许多人实际上正在阅读这篇特定的帖子,并且已经知道我们在寻找什么,并且由于 OP 提供了一个详细的问题,因此在这里提出一个高级用例是合适的。关于如何使用这些工具,我不想要一些通用示例(因为无论如何我都不应该为我的应用程序复制和粘贴它);我将阅读文档并自己弄清楚。信任但验证。
          【解决方案7】:

          您可以使用xargs,它支持一次运行多个进程。对于您的情况,它将是:

          ls -1 /main/files | xargs -I {} -P 5 -n 1 rsync -avh /main/files/{} /main/filesTest/
          

          【讨论】:

            【解决方案8】:

            我开发了一个名为:parallel_sync 的 python 包

            https://pythonhosted.org/parallel_sync/pages/examples.html

            这是一个示例代码如何使用它:

            from parallel_sync import rsync
            creds = {'user': 'myusername', 'key':'~/.ssh/id_rsa', 'host':'192.168.16.31'}
            rsync.upload('/tmp/local_dir', '/tmp/remote_dir', creds=creds)
            

            默认并行度为 10;你可以增加它:

            from parallel_sync import rsync
            creds = {'user': 'myusername', 'key':'~/.ssh/id_rsa', 'host':'192.168.16.31'}
            rsync.upload('/tmp/local_dir', '/tmp/remote_dir', creds=creds, parallelism=20)
            

            但请注意,ssh 通常将 MaxSessions 默认设置为 10,因此要将其增加到 10 以上,您必须修改 ssh 设置。

            【讨论】:

            • 异常:以下命令失败:find "./30mins" -noleaf -type f -name "*"
            【解决方案9】:

            rsync 通过网络尽可能快地传输文件。例如,尝试使用它来复制目标上根本不存在的一个大文件。该速度是 rsync 可以传输数据的最大速度。将其与scp 的速度进行比较(例如)。当目标文件存在时,rsync 在原始传输时甚至更慢,因为双方必须就文件的哪些部分进行了双向交谈,但通过识别不需要传输的数据来为自己付出代价.

            并行运行rsync 的更简单方法是使用parallel。下面的命令最多可以并行运行 5 个rsyncs,每个都复制一个目录。请注意,瓶颈可能不是您的网络,而是您的 CPU 和磁盘的速度以及并行运行只会让它们变得更慢,而不是更快。

            run_rsync() {
                # e.g. copies /main/files/blah to /main/filesTest/blah
                rsync -av "$1" "/main/filesTest/${1#/main/files/}"
            }
            export -f run_rsync
            parallel -j5 run_rsync ::: /main/files/*
            

            【讨论】:

            • 我似乎无法在 Ubuntu Server 12.04 上与 apt-get install parallel 并行。真的不想为此手动安装东西,因为它很少需要。我只是希望有一个我可以使用的快速脚本。
            • @BT643:使用apt-get install moreutils安装parallel
            • @dragosrsupercool 谢谢,当我将来需要做这样的事情时会记住这一点:)
            • 虽然是复制单个文件“尽可能快”,但很多时候似乎在单个管道上存在某种上限,因此同时传输似乎不会阻塞彼此的带宽这意味着并行传输比单次传输更高效、更快。
            • 鉴于答案链接到 GNU parallel 的网站,应该注意moreutils 包安装了一个不同的同名二进制文件。两者都将接受此答案中给出的参数,但如果您正在阅读 GNU 文档,则应使用apt-get install parallel 安装 GNU 版本。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-12-30
            • 1970-01-01
            • 1970-01-01
            • 2011-12-11
            • 2014-09-08
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多