调用 rsync 的子进程在可能的缓冲区填充后挂起

subprocess calling rsync hangs after possible buffer fill

[root@devdbadmin bin]# uname -a
Linux devdbadmin 3.10.0-693.5.2.el7.x86_64 #1 SMP Fri Oct 20 20:32:50 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
[root@devdbadmin bin]# python3.5 --version
Python 3.5.0

我遇到了一个问题,我一直未能成功调试,我正在尝试通过子进程和 python 运行 多个 rsync 命令。我花了很多时间阅读所有的陷阱,但一直没能弄清楚 运行。我不关心 rsync 的输出,也不关心 stderr/stdout。我只是在寻找成功或失败的 return 代码。发生的事情是第一个 rsync 会工作,偶尔第二个命令会工作,在任何时候 child 进程都会间歇性地停止,根据 strace 显示为超时:

select(4, NULL, [3], [3], {60, 0}) = 0 (Timeout)

我已将其缩小到子进程,因为我能够 运行 shell 中的命令没有任何问题。我认为缓冲区正在填充并导致 child 死锁或等待。根据我阅读的手册:

Warning

This will deadlock when using stdout=PIPE and/or stderr=PIPE and the child process generates enough output to a pipe such that it blocks waiting for the OS pipe buffer to accept more data. Use communicate() to avoid that

事实是,我没有在我的子进程命令中使用管道,所以我很困惑。我尝试使用 -u 调用 python 以取消缓冲,并且我尝试使用 rsync -stbuf=L 作为行。这是代码的相关部分。

subfolders = ['7/centosplus/x86_64',
              '7/updates/x86_64',
              '7/x86_64',
              'epel/7/x86_64',
              'remi/x86_64',
              'php56/x86_64',
              'nginx']

princeton_commands = [['rsync -az rsync://mirror.math.princeton.edu/pub/centos/7/os/x86_64/ 7/x86_64/'],
                      ['rsync -az rsync://mirror.math.princeton.edu/pub/centos/7/updates/x86_64/ 7/updates/x86_64/'],
                      ['rsync -az rsync://mirror.math.princeton.edu/pub/centos/7/centosplus/x86_64/ 7/centosplus/x86_64/']]

def makefolders(root_dir, subfolders):
    concat_path = functools.partial(os.path.join, root_dir)
    dir_list = list(map(concat_path, subfolders))
    logger.info('CREATING DIRECTORIES: %s' % dir_list)
    for dirs in dir_list:
        os.makedirs(dirs)

def execute_jobs(cmd):
    try:
        subprocess.run(cmds,shell=True, check=True)
        logger.info('rsync Success: %s' % cmd)
    except subprocess.CalledProcessError as e:
        logger.critical('%s FATAL: Command failed with error: %s' % (cmd,e))

def main():
    if os.path.exists(root_dir):
        logger.critical('PATH EXISTS, manually run [ rm -rf %s ] to proceed...' % root_dir)
        sys.exit(1)

    makefolders(root_dir, subfolders)
    os.chdir(root_dir)

    for cmds in princeton_commands:
        execute_jobs(cmds)

main()

我知道 linux 有一个 pipr 缓冲区,但是我没有在我的 rsync 命令上使用 -v verbose 所以我没有得到太多可以填充这个缓冲区的输出,我也没有使用管道在前面提到的子流程中。我正在使用 free 查看内存是否已满,但我没有看到任何相关内容。

重要的是,我已经尝试了多个镜像主机,认为我被限制或阻止了,但是 rsync 将在我尝试的任何主机上停止,一旦它运行到一半。

编辑:

Here is the strace and lsof of the process stuck:
root     29195  8.6  0.0 117488  2084 pts/0    S    10:47   1:54  |                       |           \_ rsync -az rsync://mirror.math.princeton.edu/pub/centos/7/updates/x86_64/ 7/updates/x86_64/

[root@devdbadmin bin]# strace -p 29195
strace: Process 29195 attached
select(4, [3], [], [3], {52, 716623})   = 0 (Timeout)
select(4, [3], [], [3], {60, 0}^Cstrace: Process 29195 detached

[root@devdbadmin bin]# lsof -p 29195 -ad  4,3
COMMAND   PID USER   FD   TYPE  DEVICE SIZE/OFF     NODE NAME
rsync   29195 root    3u  IPv4 1686385      0t0      TCP devdbadmin.afs:40500->mirror.math.princeton.edu:rsync (ESTABLISHED)
rsync   29195 root    4u   REG   253,3   786432 10755679 /u01/repo/monthly/CentOS7/2018-02/7/updates/x86_64/drpms/.python-perf-3.10.0-514.26.1.el7_3.10.0-693.5.2.el7.x86_64.drpm.g7XODd

在调试并学习了很多关于 strace/rsync、subprocess 的知识之后,我联系了官方镜像的一位管理员并解释了我的情况。他们要求我在凌晨 12 点到早上 8 点之间开始同步关闭时间。一旦这样做,rsyncs 就会正常完成。所以我认为问题是发送者 运行 没有 rsync 槽或资源来发送数据。 strace 输出显示它正在等待未获取数据的 fd。我希望这对任何人都有帮助,我希望有人可以通过查看我的 strace 来确认这一点。