Optimizar aplicacion web realizada con JSF, ICEFACES

Buenas amigos:

Este es mi primer post y acudo a los expertos esperando me puedan ayudar con un tema que tengo desde hace algunas semanas.

Tengo una aplicacion web realizada con JSF, ICEFACES y postgresql, el número máximo de usuarios que se conectan simultaneamente son 200, pero incluso con 10 personas, el sistema se a vueto lentisimo, lo raro de todo es que yo lo he usado en PC sin problemas pero los usarios se quejan de la lentitud, y sale muy seguir el error de "CONEXIÓN DE RED INTERRUMPIDA", incluso aunque el internet este estable,

Ahora bien tratando de mejorar la conexion a la base de datos, cambie el datasource con algunos parametros y el problema empeoro.

Aqui viene mi pregunta, ¿como podria mejorar el rendimiento de mi aplicación para que pueda ser más rapida y estable?

Le paso el código del datasource. No tengo mucha experiencia manejando pool de conexiones, pero este es el que implemente, espero me pueda ayudar a optimizar. De antemano muchas gracias!

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
                destroy-method="close">
                <property name="driverClassName" value="${jdbc.driverClassName}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
                <property name="initialSize" value="30"/>
                <property name="maxActive" value="30"/>
                <property name="maxIdle" value="150"/>
                <property name="minIdle" value="50"/>
</bean>
<code>

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de ezamudio

parámetros

Hay que investigar bien antes de ponerle valores a los parámetros. Tu pool puede tener hasta 30 conexiones activas, no sé por qué le pones que máximo 150 inactivas, no tiene sentido, y tampoco tiene sentido que le pongas mínimo 50 inactivas.

maxActive es el número máximo de conexiones activas, es decir, conexiones que le presta el pool a la aplicación.
maxIdle es el número máximo de conexiones inactivas, o sea las conexiones que están en el pool.
minIdle es el número mínimo de conexiones inactivas.

Si tienes minIdle en 10 por ejemplo, y maxIdle en 20, y maxActive en 50, entonces se pueden crear hasta 50 conexiones, pero en un periodo de inactividad se van a destruir las necesarias hasta quedarse sólo con 10.

En vez de minIdle y maxIdle, te recomiendo que utilices validationQuery, donde pones un SQL muy simple para mantener viva la conexión, y de ese modo no se destruyen las conexiones que se crean. También ponle maxWaitMillis para indicar cuánto tiempo debe esperar máximo el pool para obtener una conexión en caso de que tenga todas prestadas (si se llega a este lapso, se arroja excepción de que no hay conexiones disponibles).

Y te recomiendo actualizar a dbcp2, tiene bastante mejor desempeño que dbcp.

Imagen de ezamudio

cuello de botella

Por otro lado, ¿estás seguro de que el cuello de botella es el pool de conexiones? ¿Cómo llegaste a esa conclusión?

Porque podría ser la base de datos; es común que no puedas reproducir el problema porque tu copia de la base de datos para desarrollo contiene muy pocos datos y no realizas las mismas actividades que los usuarios en producción; y luego resulta que los usuarios en producción están generando reportes o consultas a tablas con muchísimos datos y entonces el problema es de desempeño de la base de datos, porque faltan índices por ejemplo.

También podría ser el contenedor o el web service que usas en producción. O la configuración del equipo donde se encuentra la aplicación. Hay muchos factores, por eso me da curiosidad saber cómo es que concluiste que el problema es el pool de conexiones, porque aunque es cierto que lo tienes muy mal configurado, me parece extraño que lo hayas identificado como la fuente del problema.

Cambie de pool

Muchas gracias ezamudio, bueno te comento realice un cambio de pool en lugar de realizarlo directamente en el código ahora lo agregue en mi glassfish, definitivamente mejoró bastante en cuanto al rendimiento.

Uso glassfish 3.1 y ahi fue donde configure el pool, con los siguientes parametros.
max-pool-size="10"
steady-pool-size="2"
idle-timeout-in-seconds="60"
max-wait-time-in-millis="1800000"

Hay todavia muchas cosas que aún no comprendo muy bien respecto a los pool de conexiones (sigo estudiandolas).

He intentado varios cambiosen max pool y steady pool, ahora me resulto otro detalle. Cuando reinicio el glassfish el sistema funciona muy bien, super rapido en todo, pero despues de un periodo de 1 a 2 horas, en algunas de mis clases me arroja una excepción.

Error en Persistencia: ; nested exception is org.springframework.dao.DataAccessResourceFailureException:
### Error querying database. Cause: org.postgresql.util.PSQLException: An I/O error occured while sending to the backend.
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### Cause: org.postgresql.util.PSQLException: An I/O error occured while sending to the backend.
; SQL []; An I/O error occured while sending to the backend.; nested exception is org.postgresql.util.PSQLException: An I/O error occured while sending to the backend.

En ocasiones me sale el error anterior y en otras este otro:

unable to get ClientInfo for connection

Se me hace raro que al reiniciar todo funcione nuevamente bien y no es todos los metodos que uso. Será acaso cuestion de otra mala configuración?

Gracias de antemano.

JNDI

Por lo que veo haces la conexión directamente desde tu proyecto, yo te aconsejaria cambiarlo por JNDI, de esta forma puedes configurar y modificar los parametros desde la consola de administración.

También puedes hacer pruebas de estres, revisar la red , que la conexion a la bd sea lo mas directa posible.

Tunera el servidor:

https://www.adictosaltrabajo.com/tutoriales/tuning/

Y no menos importante revisar las consultas, muchos usan EAGER a discreción.

También puedes agregar el cache sencillo para catalogos simples de spring, se hace en memoria, estados, estatus, paises, etc.

Ya tengo el pool en JNDI

Hola Jesus ya cambie mi pool a JNDI, y la aplicación mejoró considerablemente, pero en ocasiones me salen los errores ntes mencionados.

Imagen de javadicto

Revisa el tuneo a nivel BD

Te recomiendo que revises o que alguien que conozca PostgreSQL te apoye a revisar la configuración de la BD con la intención de mejorarla (tuneo del gestor, querys mal diseñados, creación de indices en campos que uses constantemente para tus búsquedas), también es importante que el diseño de tus tablas este normalizada a un punto medio. Puedes postear parte del código de tus Entities? Me gustaría ver como estas manejando el tema del Lazy (tablas de trabajo y catálogos). Si usas JSF es importante revisar los scope de tus ManagedBeans, que no todo sea session, el 80% de los casos te los resuelve el @viewscoped el cual libera los recursos por cambio de vista.

Saludos!

Imagen de ezamudio

keep alive

Sospecho que tu problema ahora es que las conexiones a la base de datos se "mueren" cuando hay periodos de inactividad.

Necesitas configurar el pool para que haga un keepalive a las conexiones que tiene, para mantenerlas vivas en periodos de inactividad. Generalmente le pasas un query que debe ser algo bastante inocuo (pedir la fecha, o la versión del server, etc). En dbcp por ejemplo, esta propiedad se llama validationQuery.

Imagen de Nopalin

No todo es culpa del sistema

Cuando una aplicación falla, lo primero que le viene a la mente a un usuario es que el sistema no sirve (y con sistema me refiero a codificación, funciones, algortimos, etc) y tu caso me da la apariencia que estas pensando como un usuario. Una aplicación tiene muchos más puntos donde puede fallar y no necesariamente es el software.

De inicio, ya verificaste que la red esté operando al 100%? que no haya ningún switch descompuesto que este ocasionando tráfico ó perdiendo paquetes? o algun router mal configurado?. Ésto lo comento por el error de CONEXIÓN DE RED INTERRUMPIDA que pusiste al inicio.

En segundo lugar, ya verificaste los logs de la base de datos? El error de Cause: org.postgresql.util.PSQLException: An I/O error occured while sending to the backend me da la impresión de que o está fallando el disco duro, o ya se saturó de información.

En tercero, configura postgresql para que loguee el tiempo que tarda en hacer las consultas, alomejor hay queries con mal diseño que ocasionan una sobrecarga de trabajo generando dead locks u otras cosas.

Cuando un sistema a veces funciona bien y a veces funciona bien lento, generalmente tiende a ser problema ajeno al software, a menos que cuando funciona lento el servidor este ejecutando procesos muy pesados.

Saludos