0

I am making a Java-based web server. But when I am testing it with ApacheBench, it sometimes stop responding.

On a Macbook Air:

ab -n 20000 -c 40 -d  http://localhost:1080/

is guaranteed to timeout after 16400 or more requests were done.

On Ubuntu desktop

ab -n 20000 -c 1000 -d  http://localhost:1080/

could done successfully most of the time, but sometimes stop responding after several runs.

I've identified (using Eclipse) that when the server stop responding, it is waiting for BufferedReader.readline() which I use it to read HTTP request header. But I have no idea why is it waiting.

Test code is here:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestServer {
    public static void main(String[] args){
        ServerSocket socket = null;

        try{
            socket = new ServerSocket(1080);
            ExecutorService pool = Executors.newFixedThreadPool(10);
            while(true){
                Socket s = socket.accept();
                pool.execute(new RequestHandler(s) );
            }
        }
        catch(Exception e){
            e.printStackTrace();
        }
        finally{
            if(null!=socket){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

class RequestHandler implements Runnable{
    final Socket s;
    public RequestHandler(Socket s) {
        this.s = s;
    }

    public void run() {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            String line = br.readLine();

            PrintWriter pw = new PrintWriter(s.getOutputStream());
            pw.print("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");
            pw.print(line);
            pw.flush();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally{
            if(s!=null){
                try {
                    s.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}

BTW, when writing the test code, I found something else strange

If

BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = br.readLine();

is replaced with

String line = "don't read the socket";

ab will fail with such message: "apr_socket_recv: Connection refused (111)Connection reset by peer (104)"

But open localhost:1080 with Firefox 4 will see the "don't read the socket" mess show up.

4

1 に答える 1

1

これは ApacheBench テストの意図的な部分ではないかと思います: サーバーへの接続が開かれているが、データが送信されない場合のサーバーの動作を確認するためです。おそらく ApacheBench はオープン ソースであるため、16400 回試行した後、何らかの特別な動作を呼び出すかどうかを確認できます (ソケットを開き、リクエストを送信しないことに賭けます)。

いずれにせよ、Java のバージョンがデフォルトで 0 (=無限) に設定されている場合に備えて、ソケットに明示的なタイムアウトを設定することをお勧めします。すべてのクライアントが完全に動作し、常に期待どおりのデータを正確に送信すると仮定しないでください。

したがって、一般的なルールとして、「異常が発生した」場合に Web サーバーがダウンしないようにする必要があります。ネットワークはそのようなものであり、パケット/接続がランダムにドロップされ、それに対処する必要があります。オペレーティング システムは、たとえば、接続を開くことができる時間に制限を課す可能性があるため、サーバーは突然、OS によって「足元から引っ張られた敷物」が表示される可能性があります。ApacheBench テストは、このようないくつかのグレムリンをシミュレートする可能性があると思います (これは、Ubuntu で見られるものである可能性もありますが、readLine() のハングは、おそらく、私が言及したように、開いている接続で要求を送信しないというシミュレーションです)。

于 2011-04-08T15:50:16.803 に答える