It's possible that the server never received the TCP FIN packet and
therefor did not know that it should close the IoSession.  There are
situations where a host has no way of knowing that the TCP socket has
closed unless it tries to write data to the socket and that write fails.
 This is not a limitation of MINA.  This is just the way socket I/O works.

If this is the cause of your problem, you have a couple of options.  You
could use some type of watch dog mechanisms that sends data at a regular
interval.  If the connection is no longer valid, the write will fail and
the socket will get closed thereby triggering a sessionClosed event.  Or
you could use the MINA read idle notification.  This way after a certain
amount of time has passed and your server hasn't received any data for a
particular IoSession, you can manually close the IoSession.

If your problem still persists after implementing one of these
solutions, please let us know.

-Mike

jhcha wrote:
> Dear Mina developers.
> I'm trying to use mina 1.1.5 to develop the very big stress server.
> I test my server with jmeter like some echo test now.
> 
> test environment
> 
> * jmeter :
> echo message size : 1024 bytes
> jmeter threads : 100
> loop count : 1000
> sampler : TCP Sampler
> reuse connection : false
> 
> * server : HP-UX 2 cores
>          java HotSpot(TM) Server VM (build 1.5.0.07 jinteg:03.20.07-11:05
> IA64, mixed mode) 
>          my server(mina)
>          
> * client : pc (dual core).
>          jmeter 
> 
> when I tested the stress, I found sessionCreated called counts are a little
> bigger than sessionClosed called counts.
> so, I tried to find out why that mismatch occured during several days.
> and I found the followings :
> 
> 
> org.apache.mina.common.support.IoServiceListenerSupport
> {
> 
> public void fireSessionCreated(IoSession session) {
>               SocketAddress serviceAddress = session.getServiceAddress();
> 
>               // Get the session set.
>               Set<IoSession> s = new IdentityHashSet<IoSession>();
>               Set<IoSession> sessions = 
> managedSessions.putIfAbsent(serviceAddress,
> Collections
>                               .synchronizedSet(s));
>               boolean firstSession;
> 
>               if (null == sessions) {
>                       sessions = s;
>                       firstSession = true;
>               } else {
>                       firstSession = false;
>               }
> 
>               // If already registered, ignore.
>               if (!sessions.add(session)) {
>                       return;
>               }
> 
>               // If the first connector session, fire a virtual service 
> activation
>               // event.
>               if (session.getService() instanceof IoConnector && 
> firstSession) {
>                       fireServiceActivated(session.getService(), 
> session.getServiceAddress(),
> session
>                                       .getHandler(), 
> session.getServiceConfig());
>               }
> 
>               // Fire session events.
>               session.getFilterChain().fireSessionCreated(session);  <-- 
> called
> correctly
>               session.getFilterChain().fireSessionOpened(session);  <-- 
> called correctly
> 
>               // Fire listener events.
>               for (IoServiceListener listener : listeners) {
>                       listener.sessionCreated(session);  <-- called correctly
>               }
>       }
> 
> 
> public void fireSessionDestroyed(IoSession session) {
>               boolean lastSession = false;
>               SocketAddress serviceAddress = session.getServiceAddress();
> 
>               // Get the session set.
>               Set<IoSession> sessions = managedSessions.get(serviceAddress);
>               // Ignore if unknown.
>               if (sessions == null) {
>                       // logger.error("fireSessionDestroyed() : sessions == 
> null < " +
> session);
>                       return;  <-- occured sometimes !!!!!!!!!!!!!!!!!!
>               } 
> 
>         sessions.remove(session);
> 
>               // Try to remove the remaining empty session set after removal.
>               if (sessions.isEmpty()) {
>                       lastSession = managedSessions.remove(serviceAddress, 
> sessions);
>               }
> 
>               // Fire session events.
>               session.getFilterChain().fireSessionClosed(session); <-- 
> skipped sometimes
> 
>               // Fire listener events.
>               try {
>                       for (IoServiceListener listener : listeners) {
>                               listener.sessionDestroyed(session); <-- skipped 
> sometimes
>                       }
>               } finally {
>                       // Fire a virtual service deactivation event for the 
> last session of
>                       // the connector.
>                       // TODO double-check that this is *STILL* the last 
> session. May not
>                       // be the case
>                       if (session.getService() instanceof IoConnector && 
> lastSession) {
>                               fireServiceDeactivated(session.getService(),
> session.getServiceAddress(), session
>                                               .getHandler(), 
> session.getServiceConfig()); <-- skipped sometimes
>                       }
>               }
>       }
> 
> the above fireSessionDestroyed method called as the same number as
> fireSessionCreated method.
> 
> but the mysterious event is that the sessions is not gotten from
> managedSessions in fireSessionDestroyed,
> i.e. SocketAddress key is not found in managedSessions.
> then the remaining logic was skipped.
> so fireSessionClosed, sessionDestroyed ... are not called sometimes.
> 
> [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null <
> (SOCKET, R: /172.26.73.107:15059, L: /10.88.50.205:30000, S:
> 0.0.0.0/0.0.0.0:30000)
> [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null <
> (SOCKET, R: /172.26.73.107:15961, L: /10.88.50.205:30000, S:
> 0.0.0.0/0.0.0.0:30000)
> [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null <
> (SOCKET, R: /172.26.73.107:23883, L: /10.88.50.205:30000, S:
> 0.0.0.0/0.0.0.0:30000)
> [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null <
> (SOCKET, R: /172.26.73.107:24036, L: /10.88.50.205:30000, S:
> 0.0.0.0/0.0.0.0:30000)
> [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null <
> (SOCKET, R: /172.26.73.107:31341, L: /10.88.50.205:30000, S:
> 0.0.0.0/0.0.0.0:30000)
> [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null <
> (SOCKET, R: /172.26.73.107:31343, L: /10.88.50.205:30000, S:
> 0.0.0.0/0.0.0.0:30000)
> [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null <
> (SOCKET, R: /172.26.73.107:31345, L: /10.88.50.205:30000, S:
> 0.0.0.0/0.0.0.0:30000)
> [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null <
> (SOCKET, R: /172.26.73.107:45839, L: /10.88.50.205:30000, S:
> 0.0.0.0/0.0.0.0:30000)
> [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null <
> (SOCKET, R: /172.26.73.107:5317, L: /10.88.50.205:30000, S:
> 0.0.0.0/0.0.0.0:30000)
> [IoServiceListenerSupport] - fireSessionDestroyed() : sessions == null <
> (SOCKET, R: /172.26.73.107:8471, L: /10.88.50.205:30000, S:
> 0.0.0.0/0.0.0.0:30000)
> 
> I think the reason that the 100 client threads tries to proceed "conect,
> send, receive, close",
> different sessions has the same client SocketAddress at times in server,
> and the origin of that problem is client's stress environment.
> 
> It is possible the following senario : 
> 
> I/O processor thread     I/O processor thread      client thread  client
> thread
> one                      two                       one            two
> --------------------------------------------------------------------------------
>                                                    1) connect(the same
> client SocketAddress)
> 2)fireSessionCreated
> 3)putIfAbsent
>                                                    4)disconnect
>                                                                  
> 5)connect(the same client SocketAddress)
>                           6)fireSessionCreated
>                           7)putIfAbsent
> 8)fireSessionDestroyed
> 9)remove
>                                                                  
> 10)disconnect
>                           11)fireSessionDestroyed
>                           12)get fail
> 
> 
> 
> I changed the mina source IoServiceListenerSupport.java
> 
> org.apache.mina.common.support.IoServiceListenerSupport
> ...
> 
> public void fireSessionDestroyed(IoSession session) {
>               boolean lastSession = false;
>               SocketAddress serviceAddress = session.getServiceAddress();
> 
>               // Get the session set.
>               Set<IoSession> sessions = managedSessions.get(serviceAddress);
>               // Ignore if unknown.
>               if (sessions == null) {
>                       // return;  <-- delete
>               } else {       // <-- add
> 
>                       sessions.remove(session);
> 
>                       // Try to remove the remaining empty session set after 
> removal.
>                       if (sessions.isEmpty()) {
>                               lastSession = 
> managedSessions.remove(serviceAddress, sessions);
>                       }
>               }              // <-- add
>               ....
> 
> then the Create, Destroy call mismatch was cleared.
> but I don't know this is correct solution.
> 
> Would you tell me this is correct or not?
> 
> I think this situation is very rare but... 
> I hope the mina is the best network framework 
> and this situation shoud be also considered.
> 
> 
> Thank you
> 
> J. H. Cha

Reply via email to