![将数据从一台机器快速复制到多台机器的方法](https://linux22.com/image/218471/%E5%B0%86%E6%95%B0%E6%8D%AE%E4%BB%8E%E4%B8%80%E5%8F%B0%E6%9C%BA%E5%99%A8%E5%BF%AB%E9%80%9F%E5%A4%8D%E5%88%B6%E5%88%B0%E5%A4%9A%E5%8F%B0%E6%9C%BA%E5%99%A8%E7%9A%84%E6%96%B9%E6%B3%95.png)
我发现我的工作流程存在一些瓶颈,如下所示。我确实有一台主计算机需要将数据发送到其他节点计算机。这是在 for 循环中完成的,例如:
for all nodes: rsync <Options> <Master> <Node>
如果节点数量不是很大,例如 4 或 8 个(复制时间大约 2 分钟),这会非常有效。然而,它是一条线性曲线。对于 16 个节点,大约需要 3.5 分钟,对于 128 个节点,已经需要 20 分钟(然后这个东西几乎成为我工作流程的瓶颈)。
我的目的是摆脱愚蠢的for all
循环并做更多类似的事情:
1. copy master to node1
wait & check if successfull
2. copy master to node2 && copy node1 to node3
wait & check if successfull
3. copy master to node4 && copy node1 to node5 && copy node3 to node6
wait & check if successfull
...
我的问题: bash 中是否有任何可用的内容可以帮助我做类似的事情,或者是否有更可靠的解决方案?基于IT,我在使用工具方面受到了一些限制。任何建议都受到热烈欢迎。
我想到的另一件好事可能会更好:
1. copy master data to memory
2. send the memory stuff to all nodes simultaneously (if that is possible) and all nodes write simultaneously
也许rsync
也能处理类似的事情?任何想法都受到热烈欢迎。
出于信息目的,我已经创建了一些测试脚本,如下所示,也可以进行优化。例如,这些master
东西并不是我们可以处理的必需品,node0
如master
节点。因此,代码可以进一步减少。但是,仍然存在检查,复制是否成功丢失等 - 只是作为我的想法的一个例子?你可以复制它,创建一个主文件夹,放入一些文件,然后创建128个节点。然后运行脚本并与序列副本进行比较(脚本中给出的标准方法)。即使我们只在一台机器/硬盘上工作,它的速度也更快(因此,并不真正具有代表性)。
#!/bin/bash
#
# Tobias Holzman
# 25.03.2023
#
# Description
# Script that speeds-up the function serial copying from master to nodes
# by using other nodes at which the data are already copied.
#
# Standard Approach:
# forAll(nodes, nodei)
# {
# rsync <masterData> <nodei_path>
# }
#
#------------------------------------------------------------------------------
function copyToNode ()
{
# Simple check if folder exist
if [ ! -d $1/triSurface ]
then
echo "Error"
return 0
fi
rsync -av --progress $1/triSurface $2/ > /dev/null &
return 0
}
#------------------------------------------------------------------------------
t1=$(date +%s)
# How many nodes we have (for test purpose)
nCopy=$(ls -d node* | wc -l)
nodesEmpty=()
nodesCopied=()
copyNodes=()
# Create a string array that includes all node names
for i in $(seq 0 $nCopy)
do
nodesEmpty+=("node$i")
done
echo "We need to copy the data from master to $nCopy nodes"
echo "----------------------------------------------------"
i=0
done=0
dataAtHowManyNodes=0
while true
do
i=$((i+1))
# Copy array nodesCopied which we work with in one loop
# as we dont want to change the original array
copyNodes=("${nodesCopied[@]}")
echo ""
echo " ++ Copy run #$i"
echo " ++ Remaining nodes to which we need to copy: ${nodesEmpty[@]}"
echo " ++ Available nodes used for copy : ${nodesCopied[@]}"
echo " |-> parallel copy sequences: $dataAtHowManyNodes"
# Only master copy
if [ $dataAtHowManyNodes -eq 0 ]
then
nodeToCopy=${nodesEmpty[0]}
echo " | |-> master to $nodeToCopy"
copyToNode "master" "$nodeToCopy"
# Add node to nodesCopied
nodesCopied+=("$nodeToCopy")
# Remove node from nodesEmpty
unset nodesEmpty[0]
# Update the index
nodesEmpty=(${nodesEmpty[*]})
else
for ((j=0; j<$dataAtHowManyNodes; j++))
do
echo " |-> copy sequenz $j"
nodeToCopy=${nodesEmpty[0]}
# Master to node copy
if [ $j -eq 0 ]
then
echo " | |-> master to $nodeToCopy"
copyToNode "master" "$nodeToCopy"
# Add node to nodesCopied
nodesCopied+=("$nodeToCopy")
# Remove node from nodesEmpty
unset nodesEmpty[0]
# Update the index
nodesEmpty=(${nodesEmpty[*]})
# Node to node copy
else
nodeMaster=${copyNodes[0]}
# Remove copyNode to ensure its not used again
unset copyNodes[0]
# Update the index
copyNodes=(${copyNodes[*]})
echo " | |-> $nodeMaster to $nodeToCopy"
copyToNode "$nodeMaster" "$nodeToCopy"
# Add node to nodesCopied
nodesCopied+=("$nodeToCopy")
# Update the index
nodesCopied=(${nodesCopied[*]})
# Remove node from nodesEmpty
unset nodesEmpty[0]
# Update the index
nodesEmpty=(${nodesEmpty[*]})
fi
# Check if still remaining emptyNodes
if [ ${#nodesEmpty[@]} -eq 0 ]
then
echo " ++ Done ..."
done=1
break
fi
done
fi
wait
if [ $done -eq 1 ]
then
echo ""
break
fi
dataAtHowManyNodes=$(echo "scale=0; 2^$i" | bc)
echo " |-> Data are now on $dataAtHowManyNodes nodes"
done
t2=$(date +%s)
dt=$(echo "scale=0; ($t2 - $t1)" | bc)
t=$(echo "scale=2; $dt/60" | bc)
echo "Time = $dt s ($t min)"
#------------------------------------------------------------------------------
答案1
您应该查看使用多播或广播数据帧的程序。这样主站就不会受到网络带宽的太大限制,因为所有文件都会被传输一次。
mrsync
这里可能很有趣。还有uftp
。
看https://serverfault.com/questions/173358/multicast-file-transfers
答案2
如果无法使用网络文件系统,则安装并使用GNU并行同时运行多个rsync
命令。
调整执行程序的数量,以免带宽完全饱和,因为其他人和进程需要访问系统。