运维开发网

Java NIO Selector可以选择不超过50个SelectionKeys?

运维开发网 https://www.qedev.com 2020-02-27 09:19 出处:网络 作者:运维开发网整理
我使用 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
我使用 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以上述错误终止时,我的文件服务器仍然使用固定数量的WRITABLE SelectionKey旋转,即Selector.select()保持返回固定数字,比如50.

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

我试图在没有帮助的情况下增加Socket.bind()中的积压.

可能是问题的原因是什么?

编辑

更多信息:

当使用1MB文件进行测试时,我注意到siege以Broken管道错误终止,并且文件服务器只接受了198个连接,尽管我指定了1000个并发连接x 10轮(1000 * 10 = 10000)来充斥服务器.

编辑2

我已经使用以下代码测试(单个类)来重现同样的问题,在这段代码中,我只接受连接,我不读或写,siege客户端终止连接重置或连接超时之前的管道错误.我还注意到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);
    }
}
它实际上与为ServerSocketChannel设置的默认积压值相关

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

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

mServerSocketChannel.socket().bind(new InetSocketAddress(9090),“backlog value”)

0

精彩评论

暂无评论...
验证码 换一张
取 消