Apache mina NioSocketAcceptor-X is 100% idle

I am developing a Java application using Apache Mina 2.0.16 as the NIO library. I admire the work and efforts people used to create this type of library so that NIO novices can simply create a non-blocking multi-threaded TCP server and client. After creating my own custom TCPServer class and writing the main application logic, I tried using Netbeans Java profiler to see the performance of this application.

This is a screenshot of a Java profiler: Profiler screenshot

I noticed that I have 2 NioSocketAcceptors, and this is correct because I use 2 separate TCP servers with different codec filter chains (one for connecting Java applications with Java using object serialization, and one for Java applications with C using UTF-8 or Windows-1251)., This screenshot was taken with 0 active clients on both servers. As I can see from the Java profiler, both applications run 99% of the time of the application, even when they are idle. The entire application with everything (GUI, database, timer tasks, threads ...) on Windows and Linux uses about 20% of the processor time on my gaming laptop with an Intel Core i7 processor.

This is my TCPServer Java class:

package es.modules.communication.tcp; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Map; import java.util.Set; import java.util.Timer; import java.util.TimerTask; import org.apache.mina.core.future.WriteFuture; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.service.IoServiceStatistics; import org.apache.mina.core.session.IdleStatus; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory; import org.apache.mina.filter.codec.textline.TextLineCodecFactory; import org.apache.mina.transport.socket.nio.NioSocketAcceptor; /** * * @author adrian */ public abstract class TCPServer { private final int tcp_server_port; //  ј   private final NioSocketAcceptor acceptor; //     private final IoServiceStatistics statistics; private Timer timer = new Timer("Timer for: TCP Server"); public static final int PROTOCOL_TRANSFER_OBJECT = 1; public static final int PROTOCOL_TRANSFER_UTF_8 = 2; public static final int PROTOCOL_TRANSFER_WINDOWS_1251 = 3; /** *    * * @param tcp_server_port   ј   * @param idle_timeout_sec        ќ ј *  ј  IDLE         *  * @param write_timeout_sec         * ќњ     * @param trasfer_protocol      * @throws java.io.IOException   њ  TCP  */ public TCPServer(int tcp_server_port, int idle_timeout_sec, int write_timeout_sec, int trasfer_protocol) throws IOException { this.tcp_server_port = tcp_server_port; this.acceptor = new NioSocketAcceptor(); this.acceptor.setReuseAddress(true); this.acceptor.setCloseOnDeactivation(true); this.acceptor.getSessionConfig().setWriteTimeout(write_timeout_sec); this.acceptor.getSessionConfig().setIdleTime(IdleStatus.READER_IDLE, idle_timeout_sec); switch (trasfer_protocol) { case PROTOCOL_TRANSFER_OBJECT: { this.acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory())); break; } case PROTOCOL_TRANSFER_UTF_8: { this.acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8")))); break; } case PROTOCOL_TRANSFER_WINDOWS_1251: { TextLineCodecFactory text_line_codec_factory = new TextLineCodecFactory(Charset.forName("windows-1251")); text_line_codec_factory.setDecoderMaxLineLength(64 * 1024); text_line_codec_factory.setEncoderMaxLineLength(64 * 1024); this.acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(text_line_codec_factory)); break; } } this.acceptor.setHandler(new TCPServerHandler()); this.acceptor.bind(new InetSocketAddress(this.tcp_server_port)); this.statistics = this.acceptor.getStatistics(); this.statistics.setThroughputCalculationInterval(1); this.timer.schedule(new IOStatistics(), 0, 1000); } /** *    */ public void shutdown_server() { if (this.acceptor != null && this.acceptor.isActive()) { this.acceptor.unbind(); acceptor.getManagedSessions().values().stream().forEach((ss) -> { ss.close(true); }); this.acceptor.unbind(); //Just to be sure this.acceptor.dispose(true); } } /** *     * * @return true/false / */ public boolean is_active() { return this.acceptor.isActive(); } /** * ј    * * @return ј    */ public int number_of_opened_session() { return this.acceptor.getManagedSessionCount(); } public ArrayList<String> get_all_connected_sessions() { ArrayList<String> result_list = new ArrayList<>(); Map<Long, IoSession> sessions_map = acceptor.getManagedSessions(); sessions_map.values().stream().forEach((session) -> { result_list.add(get_tcp_address(session.getRemoteAddress())); }); return result_list; } /** *  ќњ ј ј ј * * @param session TCP/IP ј * @param message  * @throws Exception   ќњ */ public void send_message_sync(IoSession session, Object message) throws Exception { WriteFuture write_future = session.write(message); if (write_future.getException() != null) { throw new Exception(write_future.getException().getMessage(), write_future.getException()); } } /** *  ќњ ј ј ј * * @param session TCP/IP ј * @param message  */ public void send_message_async(IoSession session, Object message) { session.write(message); } /** *  ќњ ј   ј * * @param sessionID   ј * @param message  * @throws Exception   ќњ */ public void send_message_sync(long sessionID, Object message) throws Exception { WriteFuture write_future = this.acceptor.getManagedSessions().get(sessionID).write(message); write_future.awaitUninterruptibly(); if (write_future.getException() != null) { throw new Exception(write_future.getException().getMessage(), write_future.getException()); } } /** *  ќњ ј   ј * * @param sessionID   ј * @param message  */ public void send_message_async(long sessionID, Object message) { this.acceptor.getManagedSessions().get(sessionID).write(message); } /** *  ќњ ј /  ј * * @param remote_tcp_address    * @param remote_tcp_port    * @param message  * @throws Exception   ќњ */ public void send_message_sync(String remote_tcp_address, int remote_tcp_port, Object message) throws Exception { for (Map.Entry entry : this.acceptor.getManagedSessions().entrySet()) { IoSession session = (IoSession) entry.getValue(); if (get_tcp_address(session.getRemoteAddress()).equals(remote_tcp_address) && get_tcp_port(session.getRemoteAddress()) == remote_tcp_port) { WriteFuture write_future = session.write(message); write_future.awaitUninterruptibly(); if (write_future.getException() == null) { return; } else { throw new Exception(write_future.getException().getMessage(), write_future.getException()); } } } throw new Exception("Threre is no session with " + remote_tcp_address + ":" + remote_tcp_port); } /** *  ќњ ј /  ј * * @param remote_tcp_address    * @param remote_tcp_port    * @param message  * @throws Exception   ќњ */ public void send_message_async(String remote_tcp_address, int remote_tcp_port, Object message) throws Exception { for (Map.Entry entry : this.acceptor.getManagedSessions().entrySet()) { IoSession session = (IoSession) entry.getValue(); if (get_tcp_address(session.getRemoteAddress()).equals(remote_tcp_address) && get_tcp_port(session.getRemoteAddress()) == remote_tcp_port) { session.write(message); return; } } throw new Exception("Threre is no session with " + remote_tcp_address + ":" + remote_tcp_port); } public void broadcast_message_sync(Object message) throws BroadCastException { boolean at_least_on_exception = false; ArrayList<Exception> error_list = new ArrayList<>(); Set<WriteFuture> write_futures = this.acceptor.broadcast(message); for (WriteFuture write_future : write_futures) { if (write_future.getException() != null) { at_least_on_exception = true; error_list.add(new Exception(write_future.getException().getMessage(), write_future.getException())); } } if (at_least_on_exception) { throw new BroadCastException(error_list); } } public void broadcast_message_async(Object message) { this.acceptor.broadcast(message); } /** * () ј  * * @param session tcp/ip ј * @param ID   ј * @param remote_tcp_address  TCP/IP  * @param remote_tcp_port  TCP/IP  */ public abstract void session_created(IoSession session, long ID, String remote_tcp_address, int remote_tcp_port); /** * () ј  * * @param session tcp/ip ј * @param ID   ј * @param remote_tcp_address  TCP/IP  * @param remote_tcp_port  TCP/IP  */ public abstract void session_opened(IoSession session, long ID, String remote_tcp_address, int remote_tcp_port); /** * () ј  * * @param session tcp/ip ј * @param ID   ј * @param remote_tcp_address  TCP/IP  * @param remote_tcp_port  TCP/IP  */ public abstract void session_closed(IoSession session, long ID, String remote_tcp_address, int remote_tcp_port); /** * ()   * * @param session tcp/ip ј * @param ID   ј * @param remote_tcp_address  TCP/IP  * @param remote_tcp_port  TCP/IP  * @param message     */ public abstract void message_received(IoSession session, long ID, String remote_tcp_address, int remote_tcp_port, Object message); /** * ()   * * @param session tcp/ip ј * @param ID   ј * @param remote_tcp_address  TCP/IP  * @param remote_tcp_port  TCP/IP  * @param message     */ public abstract void message_sent(IoSession session, long ID, String remote_tcp_address, int remote_tcp_port, Object message); /** * ()   ј * * @param session tcp/ip ј * @param ID   ј * @param remote_tcp_address  TCP/IP  * @param remote_tcp_port  TCP/IP  * @param cause  ј   */ public abstract void session_exception(IoSession session, long ID, String remote_tcp_address, int remote_tcp_port, Throwable cause); /** * ()  ј * * @param session tcp/ip ј * @param ID   ј * @param remote_tcp_address  TCP/IP  * @param remote_tcp_port  TCP/IP  */ public abstract void session_idle(IoSession session, long ID, String remote_tcp_address, int remote_tcp_port); public abstract void read_write_statisctics(String read_bytes_throughput, String written_bytes_throughput); private String get_tcp_address(SocketAddress address) { return address.toString().split(":")[0].substring(1); } private int get_tcp_port(SocketAddress address) { return Integer.parseInt(address.toString().split(":")[1]); } private class TCPServerHandler extends IoHandlerAdapter { @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { session_exception(session, session.getId(), get_tcp_address(session.getRemoteAddress()), get_tcp_port(session.getRemoteAddress()), cause); } @Override public void messageReceived(IoSession session, Object message) throws Exception { message_received(session, session.getId(), get_tcp_address(session.getRemoteAddress()), get_tcp_port(session.getRemoteAddress()), message); } @Override public void messageSent(IoSession session, Object message) throws Exception { message_sent(session, session.getId(), get_tcp_address(session.getRemoteAddress()), get_tcp_port(session.getRemoteAddress()), message); } @Override public void sessionIdle(IoSession session, IdleStatus status) throws Exception { session_idle(session, session.getId(), get_tcp_address(session.getRemoteAddress()), get_tcp_port(session.getRemoteAddress())); } @Override public void sessionCreated(IoSession session) throws Exception { session_created(session, session.getId(), get_tcp_address(session.getRemoteAddress()), get_tcp_port(session.getRemoteAddress())); } @Override public void sessionClosed(IoSession session) throws Exception { session_closed(session, session.getId(), get_tcp_address(session.getRemoteAddress()), get_tcp_port(session.getRemoteAddress())); } @Override public void sessionOpened(IoSession session) throws Exception { session_opened(session, session.getId(), get_tcp_address(session.getRemoteAddress()), get_tcp_port(session.getRemoteAddress())); } } private class IOStatistics extends TimerTask { @Override public void run() { statistics.updateThroughput(System.currentTimeMillis()); String read_bytes_throughput = String.format("%.2f", statistics.getReadBytesThroughput()); String written_bytes_throughput = String.format("%.2f", statistics.getWrittenBytesThroughput()); read_write_statisctics(read_bytes_throughput, written_bytes_throughput); } } public class BroadCastException extends Exception { final private ArrayList<Exception> error_list; public BroadCastException(ArrayList<Exception> error_list) { super(); this.error_list = error_list; } public ArrayList<Exception> getError_list() { return error_list; } } } 

I started a search on the Internet and found that in version 2.0.12 there was an error using 100% CPU, but at that time I was using 2.0.13. Nevertheless, I downloaded the latest version 2.0.16, but still the same. This is a quote from the official site.

MINA 2.0.12 released, released February 07, 2016.

This new MINA release is a bug fix release. There are several new bugs that were fixed in the closure handling method, which led to some infinite loop consuming 100% of the CPU, and a bad counter update, preventing the exit from the main loop.

From this link: https://issues.apache.org/jira/browse/DIRMINA-1006 I found a solution that requires changing the AbstractPollingIoProcessor class and adding IDLE_TIMEOUT, but I can not find the source code so that I can edit it. Here is what this AbstractPollingIoProcessor should look like: https://git1-us-west.apache.org/repos/asf?p=mina.git;a=blob;f=mina-core/src/main/java/org/apache /mina/core/polling/AbstractPollingIoProcessor.java;h=abd704580e65a2f6e381655efa971fd7ee18752e;hb=2d6f8256 .

This forum thread: http://apache-mina.10907.n7.nabble.com/MINA-hogs-the-CPU-100-with-resetWakeupSocket-td41471.html says that:

About 1.5 months ago. This worked well until a few days ago. Another interesting thing that I just noticed: when I reset the external IP address (removing it from the network adapter), the processor load increases to 0%. When I add this back, it slowly returns to what it was before (~ 78 or 100%).

I am not an expert in network configuration, and I read from wiki what nullroute means, but I can’t figure out how this will help.

I will continue to search for a solution to this problem and, if I find a solution, I will publish it.

If anyone working with Apache Mina has a solution to this problem, please help me.

+4
source share

Source: https://habr.com/ru/post/1260148/


All Articles