4

我使用siege对我的手工构建的文件服务器进行压力测试,它对于小文件(小于 1KB)非常有效,而在使用 1MB 文件进行测试时,它不能按预期工作。

下面是用小文件测试的结果:

neevek@~$ siege -c 1000 -r 10 -b http://127.0.0.1:9090/1KB.txt
** SIEGE 2.71
** Preparing 1000 concurrent users for battle.
The server is now under siege..      done.

Transactions:              10000 hits
Availability:             100.00 %
Elapsed time:               9.17 secs
Data transferred:           3.93 MB
Response time:              0.01 secs
Transaction rate:        1090.51 trans/sec
Throughput:             0.43 MB/sec
Concurrency:                7.29
Successful transactions:       10000
Failed transactions:               0
Longest transaction:            1.17
Shortest transaction:           0.00

以下是一个 1MB 文件的测试结果:

neevek@~$ siege -c 1000 -r 10 -b http://127.0.0.1:9090/1MB.txt
** SIEGE 2.71
** Preparing 1000 concurrent users for battle.
The server is now under siege...[error] socket: read error Connection reset by peer sock.c:460: Connection reset by peer
[error] socket: unable to connect sock.c:222: Connection reset by peer
[error] socket: unable to connect sock.c:222: Connection reset by peer
[error] socket: unable to connect sock.c:222: Connection reset by peer
[error] socket: read error Connection reset by peer sock.c:460: Connection reset by peer
[error] socket: unable to connect sock.c:222: Connection reset by peer
[error] socket: read error Connection reset by peer sock.c:460: Connection reset by peer
[error] socket: read error Connection reset by peer sock.c:460: Connection reset by peer
[error] socket: read error Connection reset by peer sock.c:460: Connection reset by peer
[error] socket: read error Connection reset by peer sock.c:460: Connection reset by peer

siege以上述错误终止时,我的文件服务器仍然以固定数量的WRITABLESelectionKey 旋转,即Selector.select()不断返回一个固定的数字,比如 50。

通过上面的测试,在我看来我的文件服务器不能接受不超过 50 个并发连接,因为当用小文件运行测试时,我注意到服务器有select1 个或 2 个 SelectionKeys,当用大文件运行时,它select是每次最多50个。

我试图backlogSocket.bind()没有帮助的情况下增加。

问题的原因可能是什么?

编辑

更多信息:

在使用 1MB 文件进行测试时,我注意到它因错误而siege终止Broken pipe,并且文件服务器只接受了198 个连接,尽管我指定了 1000 个并发连接 x 10 轮(1000*10=10000)来淹没服务器。

编辑 2

我已经使用以下代码(单个类)进行了测试以重现相同的问题,在此代码中,我只接受连接,我不读取写入,客户端在连接超时之前siege终止Connection reset或错误。Broken pipe我还注意到 Selector 只能选择少于 1000 个键。您可以尝试下面的代码来见证问题。

public class TestNIO implements Runnable {
    ServerSocketChannel mServerSocketChannel;
    Selector mSelector;

    public static void main(String[] args) throws Exception {
        new TestNIO().start();
    }

    public TestNIO () throws Exception {
       mSelector = Selector.open();
    }

    public void start () throws Exception {
        mServerSocketChannel = ServerSocketChannel.open();
        mServerSocketChannel.configureBlocking(false);
        mServerSocketChannel.socket().bind(new InetSocketAddress(9090));
        mServerSocketChannel.socket().setSoTimeout(150000);
        mServerSocketChannel.register(mSelector, SelectionKey.OP_ACCEPT);

        int port = mServerSocketChannel.socket().getLocalPort();
        String serverName = "http://" + InetAddress.getLocalHost().getHostName() + ":" + port;
        System.out.println("Server start listening on " + serverName);

        new Thread(this).start();

    }

    @Override
    public void run() {
        try {
            Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
            while (true) {
                int num = mSelector.select();

                System.out.println("SELECT = " + num + "/" + mSelector.keys().size());
                if (num > 0) {
                    Iterator<SelectionKey> keys = mSelector.selectedKeys().iterator();

                    while (keys.hasNext()) {
                        final SelectionKey key = keys.next();

                        if (key.isValid() && key.isAcceptable()) {
                            accept(key);
                        }

                    }
                    // clear the selected keys
                    mSelector.selectedKeys().clear();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void accept (SelectionKey key) throws IOException {
        SocketChannel socketChannel = mServerSocketChannel.accept();
        socketChannel.configureBlocking(false);
        socketChannel.socket().setSoTimeout(1000000);
        socketChannel.socket().setKeepAlive(true);
        // since we are connected, we are ready to READ
        socketChannel.register(mSelector, SelectionKey.OP_READ);
    }
}
4

3 回答 3

1

它实际上与为 ServerSocketChannel 设置的默认积压值有关

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/sun/nio/ch/ServerSocketChannelImpl.java#138

您可以通过将积压值作为第二个参数传递给 bind 方法来解决此问题。

mServerSocketChannel.socket().bind(new InetSocketAddress(9090), "积压值")

于 2014-02-08T05:10:35.870 回答
0

检查打开文件数(文件描述符)的ulimit和硬限制

我猜你正在使用linux。您可以查看limits.conf /etc/security/limits.conf

于 2012-07-09T09:48:38.507 回答
0

这个问题可能与我的代码无关,我对本地运行的 nginx 服务器(MacOSX)运行相同的测试,发生相同的错误。所以它很可能与硬件或siege客户端有关。

于 2012-07-09T16:44:23.173 回答