0

最初のコメントに続いて質問が編集されました。

私の問題は主に Java ソケットのパフォーマンス、特にターゲット サーバーからの読み取りに関するものです。

サーバーは単純な serversocket.accept() ループであり、Firefox からの接続ごとにクライアント スレッドを作成します。

主な問題は、膨大な時間ブロックするソケット入力ストリームの読み取りです。

クライアント スレッドは次のとおりです。

//Take an httpRequest (hc.apache.org), raw string http request, and the firefox socket outputstream 
private void handle(httpRequest req, String raw, Outputstream out)
{

        InputStream targetIn =null;
        OutputStream targetOut = null;
        Socket target = null;

        try {
        System.out.println("HANDLE HTTP");
            String host = req.getHeaders("Host")[0].getValue();
            URI uri = new URI(req.getRequestLine().getUri());
            int port = uri.getPort() != -1 ? uri.getPort() : 80;
            target = new Socket(host, port);


//**I have tried to play around with these but cannot seem to get a difference in performance**

            target.setTcpNoDelay(true);
//          target.setReceiveBufferSize(1024 *1024);
//          target.setSendBufferSize(1024 * 1024);


//Get your plain old in/out streams         
            targetIn = target.getInputStream();
            targetOut = target.getOutputStream();

//Send the request to the target
            System.out.println("---------------Start response---------------");
            targetOut.write(raw.getBytes());
            System.out.println("request sent to target");

        ////Same as membrane            
            byte[] buffer = new byte[8 * 1024];
            int length = 0;
            try {
                while((length = targetIn.read(buffer)) > 0) {
                    out.write(buffer, 0, length);
                    out.flush();
                }
            } catch(Exception e) {
                e.printStackTrace();
            }

            System.out.println("closing out + target socket");


//IOUTILS
//          long count = IOUtils.copyLarge(targetIn, out, 0L, 1048576L);
//          int count = IOUtils.copy(targetIn, out);
//          System.out.println("transfered : " + count );


//CHANNEL COPY
//
//          ReadableByteChannel input = Channels.newChannel(targetIn);
//          WritableByteChannel output = Channels.newChannel(out);
//          
//          ChannelTools.fastChannelCopy(input, output);
//          
//          input.close();
//          output.close();


//CHAR TO CHAR COPY         
//            int c;
//            while ((c = targetIn.read()) != -1) {
//                out.write(c);
//            }


            target.close();
            out.close();

            System.out.println("--------------------  end response   ------------------------------");
        }
         catch (Exception e) {
             // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

主な問題は、ターゲット入力ストリームをクライアント (firefox) 出力ストリームにコピーする適切な方法にあります。

これをテストするために私が使用しているサイトはhttp://www.ouest-france.fr (大量の画像があり、大量のリクエストを行う新しいサイト) です。

ワークステーションからターゲットへの Ping 時間: 10ms

iceweasel での通常の読み込み (debian firefox、firebug 時間): 14 秒、2.5MB

このプロキシの背後で読み込み中: 14 分 (firebug ネット パネルは偽の 404 でいっぱいで、一定時間後に黒に戻る要求を中止し、要求の負荷はブロックまたは待機モードになっています)

ビジュアル VM のロードアップを実行すると、(アプリが実際に時間を費やしている場所を確認するために) クラス フィルターなしでプロファイリングを開始し、その時間の 99% を java.net.SocketInputStream.read(byte[], int, int )、これはターゲット ソケット入力ストリームを読み取っています。

私は宿題を終えて、さまざまなソリューションをテストできる場所を探していたと思います。

しかし、パフォーマンスは決して向上しないようです。

私はすでに試したこと:

-入力ストリームと出力ストリームをバッファリングされたバージョンに入れますが、まったく変更はありません

-int から int へのコピー、まったく変更なし、

-classic byte[] 可変サイズの配列を使用した配列コピー、まったく変更なし

settcpnodelay、setsendbuffersize、setreceivebuffersize をいじっても、何の変化も得られませんでした。

nio socketchannels を試してみることを考えていましたが、ソケットを sslsocket ハイジャックする方法が見つかりません。

そのため、現時点では少し行き詰まっており、解決策を探しています。

私はオープンソースのプロキシのソースコードを見て、ロジックの根本的な違いを見つけることができないので、これで完全に失われています.

他のテストを試しました:

export http_proxy="localhost:4242" wget debiandvd.iso

スループットは 2MB/s に達します。また、スレッドはターゲットからの読み取りに 66% の時間を費やし、クライアントへの書き込みに 33% の時間を費やしているようです

おそらく多くのスレッドを実行する必要があると考えていますが、www.google.com でテストを実行すると、通過するリクエストははるかに少なくなりますが、それでも www.ouest-france.fr と同じ問題が発生します

Debian iso テストでは、多くのスレッドを実行する必要があると考えていました (ouest-france は約 270 リクエスト) が、Google テスト (10 リクエスト) テストでは、スレッド番号が問題ではないことを確認しているようです。

どんな助けでも大歓迎です。

環境は debian、sun Java 1.6、dev と eclipse および visualvm です。

必要に応じて残りのコードを提供できます。

ありがとうございました

4

1 に答える 1

0

部分的な解が見つかりました:

非常にクリーンなソリューションではありませんが、機能します。

まだスループットの問題があります。

私がしているのは、ソケット タイマーを通常のタイムアウト (30000ms) に設定することです。

最初の読み取りがループに入ると、タイマーをもっと低い値 (現時点では 1000 ミリ秒) にリセットします。

これにより、サーバーがデータの送信を開始するのを待つことができます。新しいデータが来ないまま 1 秒経過すると、転送が終了したと見なされます。

応答時間はまだかなり遅いですが、はるかに良くなっています。

于 2012-07-09T11:13:07.427 に答える