Mostrando las entradas con la etiqueta websphere. Mostrar todas las entradas
Mostrando las entradas con la etiqueta websphere. Mostrar todas las entradas

viernes, octubre 14, 2011

Deadlock detected al obtener las conexiones JNDI en un WAS 7.0.0.13


Hace unos días dejamos en producción una aplicación que migramos de websphere 6.1 a websphere 7. (IBM WAS 7).


En principio vale mencionar que no hay nada transparente ni "migrable" entre lo que hicimos con RAD6 para que funcione en WAS7, RAD8 no soporta SDO y tuvimos que migrar "a mano" muchas cosas re-certificando toda la aplicacion, pero eso es otro tema que no comentaré a detalle.

Lo que sí quería mencionar es un error un poco raro que tuvimos luego de la salida en producción. La aplicación en testing y desarrollo funcionaba bien, pero al estar en producción empezó a dar algunos problemas, en momentos de stress de repente el WAS se colgaba completo, inclusive dejaba de responder la consola.


Revisando el SystemOut y el SystemErr empezaron a aparecer algunos errores en la clase que obtenía la conexión a la base de datos, pero no encontramos nada que nos diera una pista de que podría dar problemas.
Vale la pena comentar que como desarrollo no teníamos acceso a los servidores por lo que el proceso de resolución fué muy tortuoso y lento.

Lo primero que verificamos, lo obvio, fué pensar que había un leak de conexiones. Revisamos el systemout buscando cualquier error que nos diera una pista del error y no encontramos nada. Recibimos algunos reportes de los administradores donde se miraba que la caída era un problema que sucedía en poco tiempo (<2 minutos). No era un proceso de degradación poco a poco sino que era una caída casi inmediata.


Sospechabamos de algún reporte o algún proceso donde por algún error hubiera algún tipo de loop infinito donde no se cerraran las conexiones. No encontramos nada.
Luego encontramos en los reportes que el total de threads que tenía configurado el WAS se ocupaban al 100%, nuestra teoría en este momento era que el leak de conexiones hacía que las peticiones se encolaran en el jndi y ocuparan threads y esto hiciera que el server se cayera.
Exploramos algunas alternativas sobre la configuración del WAS, subimos los threads disponibles, pusimos un parámetro en el JNDI para que si no recibía la conexión en 5seg que diera exception. Esto aunque sabíamos que no corregía el error nos daba lapsos más grande
s entre una caída y otra y en lugar de que el was se quedara freeze empezaría a dar error de aplicación donde podríamos encontrar la raíz del problema. Hicimos los cambios y nada. Aunque subieramos los threads igual se ocupaban todos y por alguna extraña razón no respetaba el parametro que pusimos para que diera exception si no obtenía la conexión.

Un poco desesperados peinamos el código (una aplicación grande) y revisamos todas las conexiones para incluir un best practice en cuanto a cierre de las conexiones. Probamos de nuevo y nada. Es más, los errores ocurrian más seguido.

Luego un día estando en audio con los administradores de bdd y con los administradores de WAS, tuvimos una caída. Fué entonces cuando logramos tener al fin el error en las manos. Vimos las propiedades del pool y ... sorpresa! el uso del pool estaba al 50% de su capacidad... No podía ser un connection leak si solo teníamos 50% de las conexiones usadas. Ya habíamos limpiado todos los system.out.println y el systemout estaba sin ningun tema. el systemerr tampoco tenía nada. Generaron un dump de la caída y ahí vimos entonces el error.
buscando en el javacore encontramos un Deadlock detected.
Al analizar más a detalle el lugar donde se reporta el error, vimos que el metodo que muestra la traza es un metodo del pool y que no es parte del aplicativo sino parte del driver jndi de websphere.

Buscando un poco más sobre este tema encontramos algunos casos similares al nuestro:
Y encontramos luego un problema del driver de jdbc, "PK69110: THE SERVANT ABENDS CAUSED BY HUNG THREADS IN JDBC DRIVER".
Este bug tiene afectación en la versión de WAS que usamos http://www-01.ibm.com/support/docview.wss?uid=swg1PK69110&wv=1

La versión de WAS que usamos es la 7.0.0.13, encontramos entonces el problema definitivo. Un parámetro useRRASetEquals en la configuración custom del datasource.

se hizo la prueba, se pasó a producción y luego de varias semanas tratando de encontrar el problema en nuestra aplicación vimos que es un bug de WAS.

El bug era este: Cuando yo le pido una conexión al pool, el jndi usa un objeto con las conexiones utilizadas. Este objeto es compartido. Por alguna razón al tratar de reservar una conexión en el pool el objeto se quedaba tomado por otro thread y causaba un deadlock de threads. Todo esto a nivel de los javas que hacen el pool. mientras mas usuarios trataban de obtener la conexión habían más threads que se encolaban hasta que se acababan los threads del was. Luego ni siquiera la consola de WAS funcionaba y era el freeze. Como era el objeto que reservaba la conexión el error se daba antes de que el parametro de timeout que configuramos entrara y por eso no se tomaba en cuenta.
La moraleja:
hay que leer los javacore cuando hay servers colgados... aunque sean de 500MB.

saludos!

miércoles, septiembre 16, 2009

Balanceo de Carga para dos websphere application server 6.1 usando mod_proxy_balancer

Hace varios días que vengo trabajando en un problema que me ha quitado el sueño y la tranquilidad.

Hace como mes y medio empece a leer sobre el tema de balanceo de carga desde Apache usando el mod_proxy_balancer.

http://httpd.apache.org/docs/2.2/mod/mod_proxy_balancer.html

Desde las guías todo parecía sencillo. Sinceramente no estaba muy claro de las modificaciones que se estaban planteando, pero para variar, empece a probar sin terminar de leer la documentación :p

Hice unas pruebas y asumi que todo estaba funcionando bien. El tema se quedó dormido durante algún tiempo, pero luego tuve que retomarlo desafortunadamente con las fechas ya bastante apretadas.

http://www.howtoforge.com/load_balancing_apache_mod_proxy_balancer

Me pareció excelente que se pudiera tener no solamente el balanceo de carga sino la tolerancia a fallos. De manera que si un server se caía, podía seguir operando con el otro server.

-- la version 1 de mi httpd.conf
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
ProxyRequests Off

<Proxy *>
Order deny,allow
Allow from all
</Proxy>

ProxyPass /balancer-manager !
ProxyPass / balancer://clusterWAS/ stickysession=BALANCEID nofailover=On
ProxyPassReverse / http://192.168.15.124:9080/
ProxyPassReverse / http://192.168.15.127:9080/
<Proxy balancer://clusterWAS>
BalancerMember http://192.168.15.124:9080 route=http1
BalancerMember http://192.168.15.127:9080 route=http2
ProxySet lbmethod=byrequests
</Proxy>

<Location /balancer-manager>
SetHandler balancer-manager
Order deny,allow
Allow from all
</Location>
Hice unas pruebas y asumi que todo estaba funcionando. Pero desafortunamente en ese momento no puse mucha importancia al tema de la sesion.

Al tener mi servidor balanceando carga entre los 2 nodos, la mitad de los requerimientos va a un server y la otra mitad al otro. Pero... si entro a mi aplicacion y me firmo. Esto se guarda en una variable de sesion. Y balanceando la carga se pierde.... :(

Es decir..
Pinto pantalla de login (Nodo1)
Recibo parametros de login valido y guardo variables de sesion(nodo2)
Reenvio a pantalla de inicio (Nodo1)

El problema es que en el nodo1, nunca guarde variables asi que asume que no esta firmado y vuelve a pedir la clave.

Lei un poco sobre el tema y hablaba del stickysession.

Ahora que ya entendí les cuento que la famosa stickyession es una cookie con un id de session. Que tiene 2 partes. La session y el route.
CookieJSESSIONID=00009jrrrDW78YKKVP6BTuDqqFg.-1

Esto lo pude ver gracias al pluggin firebug de firefox. Que en la pestaña de red muestra los paquetes enviados.

No obstante no lograba que funcionara en mi esquema.

Yo tengo 2 nodos con Websphere Application Server 6.1. Los 2 tienen la aplicacion instalada y funcionando.

Luego de buscar bastante y hacer bastantes pruebas encontré que la cookie de session se envía diferente en websphere que en tomcat. Y que el apache no la entendía.
CookieJSESSIONID=00009jrrrDW78YKKVP6BTuDqqFg:-1

La diferencia es el ":" en lugar del ".".

https://issues.apache.org/bugzilla/show_bug.cgi?id=42513

No hay un parque para esto en los releases.

Tuve que recompilar el apache para inlcuir la modificación en el modulo. (esto será un post aparte).
El truco no era la recompilada de apache, el truco era, la recompilada en Windows de apache :S

Bueno... luego de recompilado el apache con la recomendación que dan en el bug. Logre que la cookie tuviera el formato adecuado... pero... aun así no funcionaba!

CookieJSESSIONID=00009jrrrDW78YKKVP6BTuDqqFg.-1

Fue luego de esto cuando comprendí que el problema es que el -1 que estaba mostrando debía ser el nombre del nodo.

En algunos post, encontre que este valor es llamado route. y se configuraba en los tomcat como jvmrouteid. En websphere no encontraba nada por el estilo.

Un poco de suerte me llevo a una url donde se miraba el debug de una traza en websphere con balanceo de carga y hablaba de un Clone ID ... http://www-01.ibm.com/support/docview.wss?uid=swg27014498&aid=1

Buscando en la documentación encontre como configurarlo y funcionó.

http://publib.boulder.ibm.com/infocenter/wasinfo/v5r1//index.jsp?topic=/com.ibm.websphere.zseries.doc/info/zseries/ae/rprs_custom_properties.html
Application servers > server1 > Web container > Custom Properties

Para el nodo uno le puse un HttpSessionCloneId de "nodo1" y al otro "nodo2".

Ahora sí. Mis cookies quedaban de la siguiente forma:
para el nodo1:
JSESSIONID=0000gQCnyQMY94sb5oVXZsLU0lR:nodo1

para el nodo2:
JSESSIONID=0000gQCnyQMY94sb5oVXZsLU0lR:nodo2

Con mi apache recompilado y con mis cookies en buen estado procedí a realizar las configuraciones que me hacían falta en el apache.

Primero habilité los módulos necesarios:
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule proxy_http_module modules/mod_proxy_http.so


Luego algunos parámetros generales de la configuracion:
ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>


Configuré el balance con mis 2 nodos:
<Proxy balancer://clusterPerfilUno>
BalancerMember http://192.168.15.121:9080 route=nodo1
BalancerMember http://192.168.15.123:9080 route=nodo2
ProxySet lbmethod=byrequests
</Proxy>


donde dice "route=nodo1" es el nombre que haya puesto al cloneid en mi WAS. Luego hago el proxypass en mi aplicacion hacia el balanceo.
La stickysession la hago sobre la cookie que logre setear. Y seteo el reverse para el regreso de las conexiones.

<Location /app>
Order allow,deny
Allow from all
ProxyPass balancer://clusterPerfilUno/app stickysession=JSESSIONID nofailover=On
ProxyPassReverse http://192.168.15.121:9080/app
ProxyPassReverse http://192.168.15.123:9080/app
</Location>


Puse el loglevel en debug para rastrear posibles errores y me sale algo asi:
[Wed Sep 16 16:16:57 2009] [debug] mod_proxy_balancer.c(46): proxy: BALANCER: canonicalising URL //
clusterPerfilUno/app
[Wed Sep 16 16:16:57 2009] [debug] mod_proxy_balancer.c(280): ICON: proxy: BALANCER: Found value 00006BXDRmMTJiopXVx9UnRFUCR:nodo1 for stickysession JSESSIONID
[Wed Sep 16 16:16:57 2009] [debug] mod_proxy_balancer.c(296): proxy: BALANCER: Found route nodo1
[Wed Sep 16 16:16:57 2009] [debug] mod_proxy_balancer.c(579): proxy: BALANCER (balancer://
clusterPerfilUno) worker (http://192.168.15.121:9080) rewritten to http://192.168.15.121:9080/app
[Wed Sep 16 16:16:57 2009] [debug] mod_proxy.c(993): Running scheme balancer handler (attempt 0)
[Wed Sep 16 16:16:57 2009] [debug] mod_proxy_http.c(1920): proxy: HTTP: serving URL http://192.168.15.121:9080/app

Si no tengo buena la cookie recibo el found value (null) for stickysession JSESSIONID.

con esto logre hacer el balanceo de carga usando mod_proxy_balancer con un websphere 6.1 en los nodos.

En los proximos días estaré haciendo pruebas de esto y si encuentro algo mas lo publico.

Espero poder publicar la recompilada del apache sobre windows y también una segunda alternativa que estuve a punto de implementar.

Cabe mencionar que el IHS de IBM es una alternativa que no logre a terminar de evaluar para resolver este problema.

saludos!

viernes, marzo 27, 2009

Pool de conexiones en websphere - Connection reset

Me tope con el problema, de que en una aplicación habia un proceso que funcionaba y al rato dejaba de funcionar...

Leyendo logs encontré este error:
com.ibm.websphere.ce.cm.StaleConnectionException: Io exception: Connection reset
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:67)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)

Pero si entraba a probar la conexion funcionaba...

No estoy seguro si la conexión fue cerrada por el servidor de base de datos o por caídas de conexión, pero la conexión fue cerrada.

Cambie las propiedades del pool de conexiones para forzarlo a verificar si la conexion esta activa antes de utilizarla. Esto es ponerle un sobrecosto al ejecutar conexiones, pero nos asegura que el pool tenga conexiones disponibles y funcionales.

En propiedades avanzadas del origen de datos:Cambio la propiedad para que se prueben las conexiones:

Esto suena util si la base de datos te cierra las conexiones inactivas por cierto tiempo o si la conexion entre el servidor de aplicaciones y el servidor de base de datos es inestable.

saludos!

jueves, febrero 05, 2009

Instalar un certificado SSL en un IBM Websphere 6.1

Mas de alguna vez me he topado con el problema de instalar un certificado SSL en Java. Hoy nos toco instalarlo en un Was 6.1 (Websphere Application Server de IBM).

¿porque necesitaría instalarlo?

Porque tengo una aplicacion java instalada en el WAS que necesita consumir un servicio proveído por otra maquina mediante SSL, por ejemplo: consumir un webservice en una direccion https, crear usuarios en un LDAP, leer el contenido de un https.

¿porque es complicado?

Realmente no es muy complicado pero es un poco dificil conseguir documentacion ya que la mayoría de documentación relacionada esta orientada a Tomcat, o a configurarlo en un JVM usando herramientas como el keytool. Ademas que las busquedas en google regularmente te refieren a como instalar un SSL en tu WAS o a como conectar tu WAS a un LDAP con SSL.

¿que error me da?

Si trabajo con conexiones SSL sin tener los certificados registrados, me aparecen errores como:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: Could not find trusted certificate

Handshake terminated SSL engine: CLOSED at com.ibm.ws.webservices.engine.transport.http.HttpOutboundChannelConnection.connect(HttpOutboundChannelConnection.java:752) at com.ibm.ws.webservices.engine.transport.http.HttpsOutboundChannelConnection.connect(HttpsOutboundChannelConnection.java)

¿que debo hacer?
La idea es encontrar el lugar de almacenamiento de los certificados en JVM (keystore) y registrar los certificados de las urls en las que confiamos. Es decir si me voy a conectar a https://banco.com.gt debo de instalar el certificado de banco dentro de mi JVM.

En un tomcat buscaría el JRE que se esta ejecutando e instalaría el certificado: "keytool -keystore cacerts -trustcacerts -import -file xxx.cer".

pero para el WAS 6.1 no puedo hacerlo de esa manera.

WAS 6.0 funciono usando el keytool de la JRE que viene en WAS.

¿que debo hacer?

1. ir al sitio del banco y desde el explorador descargar el certificado.


2. En el sitio administrativo de WAS, buscar la opcion de "almacenes de claves" y desde ahi configurar los certificados:

Seleccionar las opciones de certificados firmados

y ahi busco el certificado default para el Nodo/celda en la que estoy trabajando dentro de WAS.Aqui agrego el archivo CER generado y con esta información ya dejo registrado el certificado de banco como confiable (trusted).



Luego de esto se reinicia el WAS y las aplicaciones ya encuentran los certificados como confiables y establecen la conexion.

saludos!