
Saturday January 17, 2004
JAVA.NIO ¿Lo usa alguien en un entorno de producción?
A mi me está deparando sorpresas con la ultima version de JDK.
Estoy haciendo un servidor orientado a conexion, de forma que cuando un cliente se conecta se le crea una conexion dedicada, y se le atiende por ésta de forma instantanea.
Sería algo así:
[SERVIDOR PRINCIPAL]
ServerSocket serverSocket;
//... codigo de inicializacion, etc etc
while(seguir){
Socket socket = serverSocket.accept();
ConexionCliente conexion = new ConexionCliente(socket);// implementa Runnable
Thread threadDedicado = new Thread(conexion);
threadDedicado.start();
}//while
En fin, un servidor de toda la vida. Pero mas refinado, (esto es solo un snippet) porque USA LOS PAQUETES DE NUESTRO FRAMEWORK MVC. Es decir, las Acciones no devuelven estados ni ActionFordward ni nada por el estilo. Por supuesto, la conexion no recibe el socket directamente. En su lugar tenemos clases que envuelven al socket y aportan semantica, tratamiento de errores, TIMEOUTS, etc
[CONEXION]
Sería algo parecido a:
public void run(){
while(seguir){
try{
String actionId = socket.readUtf();
Action action = Mappings.getActionPool().get(actionId);
Form actionForm = Mappings.getForm(actionId);
Request actionRequest = new Request(socket, actionForm);
ActionResult result = action.execute(actionRequest);
View view = Mappings.getView(actionId);
view.renderView(result);
}catch(IOException io){
seguir = false;
}
}//while
}
Mientras el socket.readUtf() no tenga datos (el cliente no ha pedido nada), la conexion esta
bloqueada. Cuando el cliente cierre su socket, se produce un IOException, se detiene el bucle y se liberan todos los recursos de la conexion.
El problema de todo esto es que creo un thread por socket, así que conforme crezcan los clientes los recursos de servidor se disparan.
Solucion: Patrón de diseño THREADPOOL y lecturas no bloqueantes
O eso creia. La idea es tener un Pool de Threads, y que N threads den servicios a todas las conexiones físicas (sockets). Todos los threads van quitando las conexiones de una cola (si esta vacía se suspenden hasta que otro thread no añada otra conexion) mirá si hay peticion (String action = socket.readUtf()), y si no la hay, con sockets no bloqueantes readUtf() devuelve nada luego ponemos la conexion al final de la cola y miramos en otra.
ESTA NO ES LA SOLUCION. Para entornos atomicos tipo SERVIDOR WEB seguramente si. En este tipo de entorno,
SE GASTA CANTIDAD DE CPU NADA MAS QUE VIENDO SI HAY ALGO. Espera activa.
Total, que tras ver esto, quise configurar los sockets a bloqueantes, y me he encontrado un bug muy curioso.
CON JAVA.NIO UN CHANNEL OBTENIDO DE UN SOCKET BLOQUEANTE SE CONVIERTE EN NO BLOQUEANTE TRANSCURRIDO UN TIEMPO DIOS SABE POR QUÉ. Esto hace que las conexiones recorran el ciclo de while(seguir) a lo bestia. Y esto es porque el readString() ya no bloquea.
SOLUCIONES:
- He quitado channels y todo lo que tenga que ver con NIO. He vuelto, para el modelo de 1 cliente 1 conexion - 1 thread al java.net y java.io de antes
- Voy a mirar lo de la multiplexacion. Es una caracteristica de NIO que ya existian en los programas en C.
¿Alguien se ha encontrado este problema?
(2004-01-17 08:55:24.0)
Permalink