Actualización Tomcat 9.0 y org.apache.jasper.servlet.TldScanner.scanJars
Tenia mi sistema Tomcat de una versión anterior a la 9, las 6 exactamente operando en servidor con 16 procesadores, 32 GM memoria y 1.000 conexiones trabajando muy confortablemente si ningún sobre salto , cuando nuestro proveedor de plataforma nos hace un llamado de actualización de kernel centos 6.9 a 7, cambiar a una versión superior de Tomcat y una actualización de bases de datos Postgresql , es decir de la noche a la mañana quedo nuestro sistema patas arriba, por aquello del nunca acabar agujeros de seguridad encontrados, pero donde manda capitán no manda marinero así que a lo hecho pecho, manos a la obra.
Pensé, que puede ir mal no puede ser tan complicado, es un decir porque ya en ocaciones anteriores se había tratado de migrar la aplicación y presentaba errores en el java, en el servidor, en tomcat, en conexiones, en la base de datos, en los pool de conexiones, en los cargadores de archivos, en la identificación de IP algo vital en nuestro sistema,es decir por todas partes. El problema es que ahora el cambio se hacia si o si.
Para la actualización del Kernel, nos pasaron el parche el cual se instaló sin ningún problema, bien pensé vamos sobre ruedas, solo reiniciar el equipo y todo bien todo bien.
Descargue el tomcat 9.0 del sitio de tomcat https://tomcat.apache.org/download-90.cgi , versión 64 bits para Linux, la cual hizo sin ninguna complicación.
Luego hice una copia de mi sistema Tomcat, nunca están de mas por si algo ocurre, copie la nueva en su lugar y le incorpore mis archivos de programas en la carpeta de aplicaciones webapps. Solo para que tenga en cuenta para mas adelante mi webapps costa de 257 programas o procesos diferentes.
Doy inicio y cono se esperaba NO funciono, la razón necesita java 1.8 , bueno tampoco es nada del otro mundo hago copia de mi java 1.7 y descargo el java https://www.java.com/es/download/ , también se instala sin problema salvo algunos ajustes menores en algunos programas, sobre todo actualizaciones de JAR , como commons-FileLoad.jar, mail.jar y todo lo que tenia que ver con el calculo de las IP.
De nuevo reinicio y el sistema no muestra nada, se ve que está cargando correctamente pero nada que puedo entrar al sistema, al cabo de casi, 15 minutos el sistema está arriba funcionando como un reloj, bueno pensé no me fue tan mal y me relaje.
Como las dos horas empiezan a llamar que el sistema está caído, que raro pensé hace mucho que no escuchaba esa palabra , un killall -9 java para matar todos los procesos por si las moscas y de nuevo reinicio ,esta vez se demoro como 20 minutos y al final el programa nuevamente en operación, esto si me dejo preocupado porque a pesar de los 257 programas el sistema arrancaba en menos de un minuto, ahora se demora una eternidad, voy al log y es muy grande casi 5 gigas de errores todos relacionados de un mensaje criptico para mi
org.apache.jasper.servlet.TldScanner.scanJars Al menos un JAR, que se ha explorado buscando TLDs, aún no contenía TLDs. Activar historial de depuración para este historiador para una completa lista de los JARs que fueron explorados y de los que nos se halló TLDs. Saltarse JARs no necesarios durante la exploración puede dar lugar a una mejora de tiempo significativa en el arranque y compilación de JSP
Nunca lo había visto , y desde luego mi sistema funcionaba muy bien anteriormente, busque por todas partes en Internet y era una queja relativamente amplia y la explicación la misma , pero muy confusa.
Las nuevas versión de Tomcat hacen una verificación total a todos y cada uno de los archivos JAR del sistema por todos y cada uno de los jsp que el sistema tenga y use un llamado algun procedimiento empaquetado en un archivo, se imagina 257 proceso llenos hasta el copete de archivos jsp , no se cuantos programas JAR en la carpeta /lib y WEB-INF/lib ,
algo de locos.
Alguien menciona al vuelo que son 5 segundos por cada comprobación pues súmenle, el mismo autor decía , a mi se me demora hasta dos 2 horas en subir, pensé para mi , pues no estoy tan mal, el amigo si esta jodido pero esto tiene que tener solución , no creo que no hayan pensado en eso, y me puse en la tarea de buscarla
Pues bien en casi toda parte encontré que la solución era sencilla, solo era des comentar una linea
en el archivo conf/logging.properties
org.apache.catalina.level=FINEST
Le doy iniciar de nuevo y efectivamente no funcionó.
Que pasó ?
Busco de nuevo y si hay muchos comentarios que si funciona el 8.0 pero no en el 8.5 , que en el 8.5 si funciona pero a veces no , que en 9.0 una veces no y otras tampoco , es decir una completa locura , sale uno mas desorientado de lo que entró.
Pero el problema es que dejo que eso se demore tanto tiempo o encuentro una solución de fondo, porque si cada vez que haya que iniciar el sistema se demora tanto esta fregada la cosa.
Sigo buscando, en un documento que el señor lo bendiga el autor menciona que hay dos pasos a seguir
1. En el archivo /conf/catalina.properties
tomcat.util.scan.StandardJarScanFilter.jarsToSkip=\
bootstrap.jar,commons-daemon.jar,tomcat-juli.jar,\
annotations-api.jar,el-api.jar,jsp-api.jar,servlet-api.jar,websocket-api.jar,\
bootstrap.jar,commons-daemon.jar,tomcat-juli.jar,\
annotations-api.jar,el-api.jar,jsp-api.jar,servlet-api.jar,websocket-api.jar,\
Simplemente colocarlo así
tomcat.util.scan.StandardJarScanFilter.jarsToSkip=*,\
bootstrap.jar,commons-daemon.jar,tomcat-juli.jar,\
annotations-api.jar,el-api.jar,jsp-api.jar,servlet-api.jar,websocket-api.jar,\
Observar el asterico y la coma al principio y eso es todo.
2. Insertar la linea en /conf/context.xml
<JarScanner scanClassPath="false" />
Hice el primero por sencillo , reinicio el equipo y hay si cargo como un rayo, pensé no hizo nada,
ingreso al sistema hago una pruebas preliminares y todo ok.
Ver https://tomcat.apache.org/tomcat-8.0-doc/config/jar-scanner.html del manual de Tomcat, la información hay estaba, pero no veía como se relacionaba con mi problema.
Vaya era bien sencillo. Y me quede tranquilo , como a las 2 horas me llama un asistente y me dice, Ingeniero, hay algo raro , ciertas aplicaciones no corren, y marcan en siguiente error,
javax.faces not locate
Reviso mi sistema /lib y hay está, no le veo una explicación, por puro descarte decido no usar la versión 1 de la solución e intento la 2. sugerida anteriormente, reinicio el equipo el error se soluciona pero se genera otro
ya no encuentra el JSTL
jstl.jar no locate or unknow.
El problema con la primera opción es que no busca (SCAN SKIP) los JAR y por eso ya nos los encuentra cuando los va usar
reviso nuevamente las librería y hay esta, en el /lib, entonces porque no las encuentra, buscando en Internet dicen que se recomienda altamente instalar estas librerias en el WEB-INF/lib ,
entonces eso hice con uno o 2 procesos , reinicio el servidor ese error desaparece pero surge de nuevo el problema del TLD , pero que carajos ya no estaba listo, vuelvo a mirar el archivo /logs/catalina.out , pero ya el error es especifico e indica claramente los JAR que no encuentra, que son bastantes pero manejable y los paso para /lib , reinicio el equipo y ahí si todo funciono sin problema , arranco rápido , no mostró ningún error y las pruebas fueron pasadas sin problema.
Bueno ahora si listo, como a las 6 horas , Ingeniero el sistema esta caido, que desconsuelo, me yo a tener que devolver para la versión vieja y con la gente de plataforma encima, veamos que esta pasando.
El el archivo localhost.2017-06-##.logs una sencilla linea GRAVE:memory leak. no veía ese error hacia mil años en mis sistemas.
Unas fuga de memoria pero donde y porque si todo esta trabajando bien, pensé humm no revisamos el uso de recursos de la nueva versión di por sentado que como los problemas se presentaban por archivos que no encontraba lo demás estaba bien, pues no.
Yo uso una aplicación que se llama PSI-Probe, que se fácil de instalar y trivial de configurar permite hacer un monitoreo de conectores (sockets abiertos por la base de datos), hilos ( conexiones entre Tomcat y el navegador) y desde luego consumo de memoria.
Instarlo es tan simple como descargar el WAR de sus sitio https://github.com/psi-probe/psi-probe/releases , con el único cuidado de descargar su versión particular de Tomcat, en este caso como estaba con Tomcat 9 descargue la ultima versión 3.0.0 .
configuro el sistema en /conf/tomcat-users.xml
<role rolename="probeuser"/>
<user username="myprobe" password="1234" roles="manager-gui"/>
<user username="myprobe" password="1234" roles="manager-gui"/>
donde myprobe es mi usuario probe y 1234 la clave
El war descargado lo ingreso en mi carpeta /webapps y reinicio el equipo , arranco sin problema, y empiezo a monitoreo , hilos, conectores, memoria , aparentemente sin problema , luego en la hora pico , la porción de memoria G1 Old GEN, empieza a crecer , nada porque desesperarse pensé, pero el problema fue que no paro, era lento pero constante hasta que al final el sistema se cayó de nuevo.
Lo reinicio y empezamos nuevamente el proceso y ocurrió lo mismo era muy lento podía demorar hasta 10 horas pero indefectiblemente se queda sin memoria por consumo del G1 Old Gen, buscando en Internet explican que el modelo de uso de memoria de java 1.8 cambio, para hacerla mas dinámica y evitar que hacer tantos tunning al los sistemas periféricos y satélites del sistema principal por ejemplo el Pgpool (pool de conexiones de la base de datos) , los manejadores gráficos etc, pero no encontré mucha información acerca cual es el ideal de la nueva configuración de memoria, lo que si decían claro es que Tomcat 9.0 consume muchísima mas memoria que sus antecesores.
Leyendo los parámetros de configuración de estas y las distintas opciones por pura sospecha escojo dos valores que me parecieron podían ayudar , dado que el problema se presenta en el G1 Old Gen , es decir en la carga de las versiones mas viejas de la porción de memoria que se esta usando y que el sistema guarda por así decirlo en cache.
En el archivo /tomcat/bin/setenv.sh coloque lo siguiente después de eliminar varias opciones que dicen los que saben que ya no se usan como PermSize por ejemplo
Lo deje como:
JAVA_OPTS="-server -Djava.awt.headless=true -XX:+UseG1GC \
-Xmn256m -Xms1024m -Xmx2048m -XX:CMSInitiatingOccupancyFraction=65"
-Xmn256m -Xms1024m -Xmx2048m -XX:CMSInitiatingOccupancyFraction=65"
cambiar permisos
# chmod /ugo+wrx /usr/local/tomcat/bin/setenv.sh
El -XX:CMSInitiatingOccupancyFraction=65 le indica al sistema que no permita que la memoria se desborde porque cuando supere el 65% debe recalcular el Old Gen ,
-XX:+UseG1GC , permite una recolección mas eficiente y precisa en sistemas de varios procesadores
Los valores -Xms1024m -Xmx2048m lo ajuste de ultimo haciendo pruebas de prueba y error para mantener el sistema con un G1 Old GEN bajo, que a mi hasta el momento me viene funcionado muy bien, todo esto esta sujeto a sus sistema particular, para poder hacerlo creo es indispensable un buen sistema de monitoreo de memoria como PSI Probe..
Por ultimo pero no menos importante y que lo hice ya por aprovechar todos los cambios y usar el tomcat 9.0 como se debe, cambie el modo de conexión de BIO a NIO (dice la documentación que va hacer el modo de conexión por defecto de Tomcat), que hace un uso de los recursos del sistema de conexión y sockets mucho , mucho mas eficiente, las lecturas del Psi Probe me dejó gratamente impresionado.
El cambio fue el siguiente en el archivo /bin/server.xml
Comenté el BIO e instale lo siguiente
<!--
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
-->
Inserte el siguiente script, Observar que esencialmente el cambio es de protocolo
<Connector connectionTimeout="20000"
maxThreads="1000"
port="8080"
protocol="org.apache.coyote.http11.Http11NioProtocol"
redirectPort="8443"/>
Sin más, lanzo mi servidor , y ahora si, que maravilla.
Después de tanta carreta tener en cuenta al hacer el cambio a tomcat 9.0
1. En el archivo conf/logging.properties , des comentar
org.apache.catalina.level=FINEST
2. Insertar la linea en /conf/context.xml
<JarScanner scanClassPath="false" />
Estos dos pasos para saltearse la demora en la carga debido a la búsqueda de los TLD en los archivos JAR
3. Colocar los archivos jstl.jar de acuerdo a la recomendación del proveedor en la carpeta /WEB-INF/lib
Analizar cuales archivos deben ir en realidad en /lib y cuales en WEB-INF/lib , los otros Tomcat diferentes al 9, eran muy liberales en eso, pero hay hay que ponerle cuidado si no se quiere tener un sistema con una tiempo de carga muy alto, hay claro archivos que no importa donde los coloque marcan el WARNING INFO , hay nada que hacer , pero la cosa si se hace bien mejora muchísimo
3, en el archivo /tomcat/bin/setenv.sh
JAVA_OPTS="-server -Djava.awt.headless=true -XX:+UseG1GC \
-Xmn256m -Xms1024m -Xmx2048m -XX:CMSInitiatingOccupancyFraction=65"
Para evitar problemas de sobre carga de memoria , los expertos recomiendan un valor
entre 60 y 70 , dependiendo de la cantidad de memoria y la cantidad de aplicaciones concurrentes.
4. en el archivo /bin/server.xml , colocar el siguiente código teniendo en cuento el protocolo.
<Connector connectionTimeout="20000"
maxThreads="1000"
port="8080"
protocol="org.apache.coyote.http11.Http11NioProtocol"
redirectPort="8443"/>
Para tener un uso eficiente de recursos y usuarios concurrentes , he tenido onectados simultaneas más de 1.000 conexiones durante un lapso de mas de 8 horas continuas de conexión sin des conexiones, (Son puntos de venta) y el sistema suave como una seda , alto desempeño, poco uso de memoria y bajo uso de sockets. (gracias a PSI PROBE, me fue de mucha ayuda)
Todo es Sencillo si se sabe como.
Muchas gracias Carlos, una explicación de maravilla.
ResponderEliminarbuenisimo
ResponderEliminar