Java NiO selector can select no more than 50 selectionkeys?
I used siege to stress test my manually built file server. It is suitable for small files (less than 1KB), but it can't work as expected when testing with 1MB files
The following are the results of testing with small files:
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
The following are the results of the test using a 1MB file:
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
When the above error of siege terminates, my file server still uses a fixed number of writeable selectionkey rotations, i.e. selector Select () keeps returning a fixed number, such as 50
Through the above test, in my opinion, my file server cannot accept no more than 50 concurrent connections, because when running the test with a small file, I noticed that the server selects 1 or 2 selectionkeys. When running a large file, it selects at most 50 at a time
I tried to add socket without help Backlog in bind()
What may be the cause of the problem?
edit
More information:
When testing with 1MB files, I noticed that the siege terminated with a broken pipe error, and the file server only accepted 198 connections, although I specified 1000 concurrent connections x 10 rounds (1000 * 10 = 10000) to flood the server
Edit 2
I have used the following code test (single class) to reproduce the same problem. In this code, I only accept connections, I don't read or write, the siege client terminates the connection, resets the pipeline error before the connection times out I also noticed that the selector can only select less than 1000 keys You can try the following code to witness the problem
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); } }
Solution
It is actually related to the default backlog value set for serversocketchannel
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/sun/nio/ch/ServerSocketChannelImpl.java#138
You can solve this problem by passing the backlog value as the second parameter to the bind method
mServerSocketChannel. socket(). bind(new InetSocketAddress(9090),“backlog value”)