あるコンピュータから複数のコンピュータにデータをすばやくコピーする方法

あるコンピュータから複数のコンピュータにデータをすばやくコピーする方法

以下のように、ワークフローでいくつかのボトルネックが見つかりました。別のノードコンピュータにデータを送信する必要があるマスターコンピュータがあります。これは 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はありません。したがって、コードをさらに減らすことができます。しかし、コピーが成功したかどうかなどはまだ確認されています。 - 私が考えるものの例ですか?これをコピーし、マスターフォルダを作成し、その中にいくつかのファイルを入れて、128個のノードを作成できます。次にスクリプトを実行し、シーケンスのコピーと比較します(スクリプトで提供されている標準的な方法)。 1つのシステム/ハードドライブでのみ作業しても速度が速くなります(したがって代表性はありません)。node0master

#!/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同時に複数のコマンドを実行します。

他の人とプロセスがシステムにアクセスする必要があるため、帯域幅が完全に飽和しないようにランチャーの数を調整してください。

関連情報