2

1 秒あたり 50 万から 100 万のリモート関数呼び出しを実現したいと考えています。Central計算を開始するコンピュータが1台と、計算Workerを実行するコンピュータが 1 台あるとします。実際の構成では、多くのワーカー コンピューターが存在します。

ちょっとの間、私たちの仕事は を計算することだとしましょうsum of [(random int from 0 to MAX_VAL)*2], PROBLEM_SIZE times 非常に素朴なプロトタイプは

Worker:

//The real function takes 0.070ms to compute.
int compute(int input) {
    return input * 2;
}

void go() {
    try {
        ServerSocket ss = new ServerSocket(socketNum);

        Socket s = ss.accept();
        System.out.println("Listening for " + socketNum);

        DataInput di = new DataInputStream(s.getInputStream());
        OutputStream os = s.getOutputStream();
        byte[] arr = new byte[4];
        ByteBuffer wrap = ByteBuffer.wrap(arr);

        for (; ; ) {
            wrap.clear();

            di.readFully(arr);
            int value = wrap.getInt();
            int output = compute(value);

            wrap.clear();
            byte[] bytes = wrap.putInt(output).array();
            os.write(bytes);
        }

    } catch (IOException e) {
        System.err.println("Exception at " + socketNum);
        e.printStackTrace();
    }
}

Central:

void go(){    
    try {

        Socket s = new Socket(ip, socketNum);
        s.setSoTimeout(2000);
        OutputStream os = s.getOutputStream();
        DataInput di = new DataInputStream(s.getInputStream());

        System.out.println("Central socket starting for " + socketNum);

        Random r = new Random();

        byte[] buf = new byte[4];
        ByteBuffer wrap = ByteBuffer.wrap(buf);

        long start = System.currentTimeMillis();
        long sum = 0;

        for(int i = 0; i < n; i++) {
            wrap.clear();
            int value = r.nextInt(10000);

            os.write(wrap.putInt(value).array());

            di.readFully(buf);
            wrap.clear();

            int answer = wrap.getInt();
            sum += answer;
        }

        System.out.println(n + " calls in " + (System.currentTimeMillis() - start) + " ms");
    } catch(SocketTimeoutException ste) {
        System.err.println("Socket timeout at " + socketNum);
    }

    catch (Exception e) {
        e.printStackTrace();
    }

ping が 0.150 ミリ秒で、1 スレッドのワーカーと 1 スレッドのセントラルを実行する場合、各反復には約 0.150 ミリ秒かかります。パフォーマンスを向上させるためNに、Worker と Central の両方でスレッドを実行します。 n-th スレッドは port をリッスンします2000+n。各スレッドが停止した後、結果を合計します。

ベンチマーク

最初に、私の仲間の学校のネットワークで上記のプログラムを実行しました。次に、2 つの Amazon EC2 クラスター インスタンスで実行しました。結果のギャップは非常に大きかった。

CHUNK_SIZE = 100_000すべての実行で。

フェローのネットワーク:

3 年前は最上位の構成 (Xeon E5645) だったと思います。マシンが 20 台しかないため、並列計算用に大幅に最適化されており、LAN トポロジーが単純になっていると思います。

OS: Ubuntu

平均ping: ~0.165ms

N=1 total time=6 seconds 
N=10 total time=9 seconds
N=20 total time=11 seconds
N=32 total time=14 seconds
N=100 total time=21 seconds
N=500 total time=54 seconds

アマゾンネットワーク:

同じ配置グループで開始された 2 つの Cluster Compute Eight Extra Large インスタンス (cc2.8xlarge) でプログラムを実行しました。

OSはアマゾンのLinuxです

平均 ping: ~0.170ms。

結果は少し残念でした:

N=1 total time=16 seconds 
N=10 total time=36 seconds
N=20 total time=55 seconds
N=32 total time=82 seconds
N=100 total time=250 seconds
N=500 total time=1200 seconds

各構成を 2 ~ 4 回実行しましたが、結果はほぼ同じで、ほとんどが +-5% でした

関数呼び出しあたり 0.170 ミリ秒 = 1 秒あたり 6000 呼び出し = 16 秒あたり 100_000 呼び出しであるため、Amazon N=1 の結果は理にかなっています。Fellow のネットワークの 6 秒は、実際には驚くべきことです。

最新のネットワークでの 1 秒あたりの最大 TCP パケット数は、1 秒あたり約 40 ~ 70k だと思います。N=100、time=250 秒に相当します: N*CHUNK_SIZE / time = 100 * 100_000packets / 250sec = 10_000_000packets / 250sec = 40_000packets/second.

問題は、特に N 値が高い場合に、フェローのネットワーク/コンピューター構成がどのようにうまく機能したかということです。

私の推測では、最大 40 バイトのオーバーヘッドがあるため、4 バイトのリクエストと 4 バイトの応答をそれぞれ個別のパケットに配置するのは無駄です。これらすべての小さなリクエストを、たとえば 0.010 ミリ秒分プールして 1 つの大きなパケットに入れ、対応するソケットにリクエストを再分配するのが賢明です。アプリケーション レベルでプーリングを実装することは可能ですが、Fellow のネットワーク/OS はそれを行うように構成されているようです。

更新: java.net.Socket.setTcpNoDelay() で遊んだことがありますが、何も変わりませんでした。

究極の目標: 非常に大きなツリーを使用して、数百万の変数で方程式を近似します。現在、200_000 ノードのツリーが RAM に収まります。しかし、何百万ものノードを持つツリーを必要とする近似方程式に興味があります。数テラバイトの RAM が必要です。アルゴリズムの基本的な考え方は、ノードからリーフへのランダムなパスを取り、それに沿って値を改善することです。現在、プログラムは 32 スレッドで、各スレッドは 1 秒あたり 15000 回の反復を実行します。1秒あたりの反復回数が同じクラスターに移動したいと思います。

4

1 に答える 1

1

Nagle アルゴリズムの有効化を検討している可能性があります:ウィキペディアのエントリ

役立つかもしれない無効化に関するリンクは次のとおりです。LinuxでNagleのアルゴリズムを無効にする

于 2013-02-22T14:57:17.277 に答える