Tuning de Weblogic 11g (I)

Históricamente, y desde que migramos, en nuestra plataforma Linux, de Weblogic 8.1 a Weblogic 11g, el servidor en el que desplegamos nuestras aplicaciones tarda bastante en alcanzar el estado RUNNING.

Dentro de las tareas de optimización teníamos claro que había que aligerar el arranque de nuestro dominio en weblogic 11g. Descartando eliminar del dominio alguna de las aplicaciones desplegadas, nos pusimos a investigar donde se estaban perdiendo los tiempos.

Un estudio minucioso del arranque del dominio examinando las trazas nos mostró que durante un tiempo, más o menos largo dependiendo de la potencia de la máquina, weblogic quedaba parado aparentemente sin realizar ninguna operación. La última traza que se escribía, antes de la espera, era la siguiente:

<31-mar-2011 14H57’ CEST> <[STANDBY] ExecuteThread: ‘2’ for queue: ‘weblogic.kernel.Default (self-tuning)’> <> <> <> <1301576265940>

Las siguientes trazas, pasado el tiempo de espera, eran las siguientes:

<31-mar-2011 15H00’ CEST> <[ACTIVE] ExecuteThread: ‘0’ for queue: ‘weblogic.kernel.Default (self-tuning)’> <> <> <> <1302021589143>
 <31-mar-2011 15H00’ CEST> <[ACTIVE] ExecuteThread: ‘0’ for queue: ‘weblogic.kernel.Default (self-tuning)’> <> <> <> <1302021589205>
 <31-mar-2011 15H00’ CEST> <[ACTIVE] ExecuteThread: ‘0’ for queue: ‘weblogic.kernel.Default (self-tuning)’> <> <> <> <1302021589257>

Las trazas revelaban que entre el inicio del subsistema IIOP y el subsistema Security pasaba un tiempo de tres minutos en los que el servidor no mostraba ninguna traza. Así pues, un buen punto de partida era investigar en que se estaban empleando esos minutos de espera.

Consultando información sobre este problema en internet surgieron varios casos similares con sus respectivas soluciones.

La información corrupta de ldap.

El primer camino que investigué hablaba de corrupción en la información almacenada referente a ldap en el dominio. Esta información, supuestamente incorrecta, habría sido generada en un arranque previo.

La solución propuesta estaba basada en renombrar o directamente eliminar el directorio ldap almacenado en la instancia o instancias del servidor en el dominio. Este directorio ldap se puede encontrar en la ruta /servers//data.

Seguí este intento de solución, ya que las trazas escritas después de la parada mostraban el arranque de los recursos JPA (Java Persistence API) y JDO (Java Data Objects) cuya autenticación parecía estar basada en ldap.

Sin embargo, y tras eliminar el directorio y reiniciar el dominio, los tiempos ni mejoraron ni empeoraron, se mantuvieron similares.

Quedaba claro, por tanto, que esta no era la solución requerida.

La semilla de seguridad que germinaba tiempos de espera.

En esta bifurcación de soluciones, el siguiente camino a seguir hablaba de mal rendimiento provocado por el sistema de seguridad de java, cuya solución estaba basada en modificar el fichero java.security de la JRE con la que se arrancan los dominios.

La modificación a realizar en este fichero era sustituir la línea:

securerandom.source=file:/dev/urandom

por:

securerandom.source=file:/dev/./urandom

No entendía yo muy bien en que podía afectar este cambio al arranque de weblogic, así que escepticismo es el sentimiento que mejor definía mi estado. Sin embargo, como el subsistema que parecía estar dando los problemas era el de Security, me decidí a intentarlo.

Sorprendentemente, tras realizar el cambio y reiniciar el dominio, el tiempo de espera entre el arranque de los dos subsistemas desapareció.

<31-mar-2011 18H39’ CEST> <[STANDBY] ExecuteThread: ‘2’ for queue: ‘weblogic.kernel.Default (self-tuning)’> <> <> <> <1301576265940>
 <31-mar-2011 18H39’ CEST> <[ACTIVE] ExecuteThread: ‘0’ for queue: ‘weblogic.kernel.Default (self-tuning)’> <> <> <> <1302021589143>
 <31-mar-2011 18H39’ CEST> <[ACTIVE] ExecuteThread: ‘0’ for queue: ‘weblogic.kernel.Default (self-tuning)’> <> <> <> <1302021589205>
 <31-mar-2011 18H39’ CEST> <[ACTIVE] ExecuteThread: ‘0’ for queue: ‘weblogic.kernel.Default (self-tuning)’> <> <> <> <1302021589257>
 <31-mar-2011 18H39’ CEST> <[ACTIVE] ExecuteThread: ‘0’ for queue: ‘weblogic.kernel.Default (self-tuning)’> <> <> <> <1302021589510>

En las trazas se puede observar que el arranque de los dos subsistemas se realiza dentro del mismo minuto, un estudio más detenido demuestra que lo hace casi en el mismo segundo.

Por tanto, estaba claro que ésta era la solución para este retraso concreto.

Sin embargo, y pese a tener la solución, no me quedaba claro el por qué de la misma, así que seguí investigando.

/dev/urandom

De esta forma me surgieron preguntas para las que no tenía respuesta. Algunas de estás preguntas eran: ¿qué era /dev/urandom? ¿para qué lo estaba usando el sistema de seguridad de java? ¿por qué ralentizaba el proceso de autenticación?

Así que comencé a buscar respuestas.

La primera respuesta que encontré fue la utilidad de /dev/urandom, un archivo especial que se puede encontrar en los sistemas unix, que basándose en los bits que genera el ruido ambiental recogido de dispositivos obtiene números pseudoaleatorios. Estos números pseudoaleatorios son ideales para utilizar en la generación de claves. Si queréis saber más podéis leer la entrada sobre /dev/random de la wikipedia. Para comprobar que era eso de la generación de números aleatorios a partir del ruido de los dispositivos, se me ocurrió hacer un cat del fichero /dev/urandom. El resultado fue el siguiente: wpid-captura_de_pantalla_2011-04-05_a_las_20-thumb-51-37_sepia_sepia-2012-02-27-19-29.png



java.security.SecureRandom

La siguiente pregunta era saber para que estaba utilizando java el fichero /dev/urandom.

La respuesta la encontré en la clase java.security.SecureRandom. Esta es la clase que proporciona la generación de números aleatorios adecuados para implementar potentes sistemas de cifrado.

Cuando desde un desarrollo se utiliza esta clase, desde la variable securerandom.source del fichero //jre/lib/security/java.security, se recoge el sistema de generación de números aleatorios que java utilizará internamente para su generación.

La configuración, que por defecto se crea con la instalación de la jdk, es el fichero /dev/urandom como se puede comprobar en la jdk 1.6.0_21que tengo instalada en mi entorno de desarrollo.

Select the source of seed data for SecureRandom. By default an 
attempt is made to use the entropy gathering device specified by
the securerandom.source property. If an exception occurs when
accessing the URL then the traditional system/thread activity
algorithm is used.
 On Solaris and Linux systems, if file:/dev/urandom is specified and it
exists, a special SecureRandom implementation is activated by default.
This “NativePRNG” reads random bytes directly from /dev/urandom.
 On Windows systems, the URLs file:/dev/random and file:/dev/urandom
enables use of the Microsoft CryptoAPI seed functionality.
 securerandom.source=file:/dev/urandom

Entonces, ¿qué es lo que funciona mal?

Hasta aquí todo parece normal, ¿qué es entonces lo que no funciona?. La respuesta a esta pregunta la encontré en la base de datos de bugs que Sun (ahora Oracle) comparte en el portal bugs.sun.com. Al parecer y reportado desde la versión Java 5.0 existe el bug 6202721.

Este bug dice que si se utilizan las siguientes líneas de código en cualquier desarrollo java

 SecureRandom.getInstance(“SHA1PRNG”).nextLong());

la clase SecureRandom lee las semillas del fichero /dev/random en vez del fichero /dev/urandom configurado en la opción securerandom.source del fichero java.security.

Esta casuística fue introducida como corrección de otro bug (4705093) que no he sido capaz de encontrar en la base de datos. Al parecer, este bug le daba algún tipo de significado especial a la cadena /dev/urandom que impedía utilizarla siendo sustituida por /dev/random. La utilización de éste fichero es un problema porque proporciona un rendimiento muchísimo peor.

La solución.

Existen dos soluciones propuestas a este problema.

Si somos nosotros los que hemos incorporado en nuestro desarrollo las líneas de código que obtienen un número aleatorio basado en el algoritmo SHA1PRNG, bastará con sustituir las líneas:

 Long numeroAleatorio = SecureRandom.getInstance(“SHA1PRNG”).nextLong());

por las siguientes:

 Long numeroAleatorio = new SecureRandom().nextLong();

Sin embargo, si no tenemos acceso a los fuentes del código para cambiarlo, tal y como ocurre en el arranque del subsistema security en Weblogic; la solución es modificar el valor de la opción securerandom.source en el fichero java.securityde la instalación de la JRE con el siguiente valor:

 securerandom.source=file:/dev/./urandom

De esta forma, la JRE no detectará la cadena /dev/urandom y por tanto no procederá a sustituirla por /dev/random. Sin embargo, en unix, la ruta /dev/./urandom hace referencia al mismo fichero que la ruta /dev/urandom, por lo que el funcionamiento será el mismo y el rendimiento será el óptimo.

Y así, es como finaliza esta investigación que viene a demostrar las infinitas complejidades que surgen en los desarrollos basados en Java.

Espero que os haya sido útil e interesante.

Minientrada

Error increible de Java con Windows 7

En el mundillo Java los fallos a veces pasan, y a veces pasan sin ser culpa de Java. Y esas veces hay que celebrarlo, porque son las menos.

Coincidiendo con la migración de Windows XP a Windows 7 en los entornos de usuario, una de nuestras aplicaciones java realizada con tecnología RCP (Rich Client Platform), decidió sin previo aviso que no quería arrancar. Los síntomas eran claros, al pinchar sobre el ejecutable, en nuestra recién estrenada instalación de Windows 7, la aplicación comenzaba el arranque y se cerraba sin llegar a mostrar la ventana inicial. Lo que nos extrañaba es que la misma versión de la aplicación en Windows XP funcionara correctamente.

El error.

En una aplicación cliente, relativamente «compleja», como es ésta; con accesos a base de datos mediante JDBC, con clientes EJB que se conectan a EJBs publicados en un servidor J2EE, e informes generados con BIRT, muchas variables podían influir en el mal funcionamiento. Lo que no sospechaba, ni por asomo, es que algo tan tonto como el tipo de letra pudiera influir en una aplicación java, sin embargo la ejecución de la aplicación RCP era clara al respecto ya que las trazas dejaban el siguiente rastro:

java.util.MissingResourceException: Wrong font data format. Value is: «MS Sans Serif-negrita-12 «

at org.eclipse.jface.resource.FontRegistry.makeFontData(FontRegistry.java:767)

at org.eclipse.jface.resource.FontRegistry.readResourceBundle(FontRegistry.java:860)

at org.eclipse.jface.resource.FontRegistry.readResourceBundle(FontRegistry.java:342)

at org.eclipse.jface.resource.FontRegistry.(FontRegistry.java:286)

at org.eclipse.jface.resource.FontRegistry.(FontRegistry.java:308)

at org.eclipse.jface.resource.JFaceResources.getFontRegistry(JFaceResources.java:342)

 

Windows 7 y los DPI de las fuentes.

 

Los monitores planos (LCD, TFT…) tienen un tamaño fijo de pixel o «resolución» con la que muestran los elementos en pantalla. Cuando un usuario, desde el sistema operativo, cambia a una resolución menor para ver más grande el tamaño de la letra, el monitor combina y ajusta los pixeles de tamaño fijo para conseguir la nueva resolución. Este proceso degrada la calidad de la imagen vista en pantalla haciendo que todo, no solo el texto, se vea peor.

Para evitar esto, Windows permite el aumento de tamaño de las fuentes y de las ventanas manteniendo la resolución nativa del monitor. Gracias a este método se obtienen imágenes más nítidas al poder utilizar el tamaño original de los píxeles para componerlas.

En Windows 7, para hacer que la resolución del sistema operativo corresponda con la resolución nativa de la pantalla y en ciertas resoluciones altas, para que las letras se muestren a un tamaño aceptable establece por defecto la configuración 120 DPI (dots per inch) de las fuentes. La configuración normal de las fuentes es 96 DPI. Esto implica que en 120DPI se usa un 125% de DPI más grande que lo habitual.

Si el usuario vuelve a 96 DPI, es decir, vuelve al tamaño de fuente normal, las fuentes TrueType, que permiten escalado, se ajustan automáticamente. Sin embargo, las fuentes basadas en bitmaps (imágenes), como MS Sans Serif, deben utilizar el fichero de fuentes adecuado a la resolución. Por tanto, en la instalación de Windows 7 debería existirá un fichero de fuentes para 96DPI y otro para 120DPI.

Sin embargo, si a la hora de instalar Windows 7 la resolución de pantalla es una resolución alta (por ejemplo, 1900×1200) se establece las fuentes por defecto a 120 DPI y no se instalan las fuentes 96 DPI ya que se considera que no se van a utilizar.

Por tanto, si se utiliza el tamaño 96DPI, se encontrará con que para ciertos tipos de letra los ficheros no existen, y como en nuestro caso, dará un error. La aplicación RCP utiliza un sistema de ventanas que lo independiza del sistema operativo. Este sistema de ventanas es conocido como JFace y está basado en SWT (Standar Widget Tookit). Este sistema utiliza las fuentes normales de 96DPI y todo junto provoca el fallo.

Las soluciones. Considerando las particularidades de nuestro entorno se puede optar por varias soluciones. A continuación se muestran en orden de prioridad:

 

  • Incluir las fuentes 96DPI en la instalación de Windows 7.
  • Cambiar el tipo de fuente que utiliza la aplicación RCP para que use una fuente TrueType (que no dan problemas en el escalado).
  • Parchear Windows 7 para que utilice las fuentes 120DPI cuando de fuentes bitmap se trata.

 

Incluir las fuentes 96DPI en la instalacion de Windows 7 Las fuentes en Windows 7 se instalan de diferentes maneras. El método más sencillo es descargar la fuente, descomprimirla, hacer doble click en el archivo .FON y finalmente hacer click en el botón «Instalar».

Las fuentes se pueden descargar desde los siguentes links:

Cambiar el tipo de fuente de la aplicación RCP

La aplicación RCP utiliza jFace para la implementación de la interfaz de usuario. Es en esta interfaz donde se configuran los tipos de fuente que se utilizan en la aplicación. La configuración se realiza en el fichero jfacefonts_es.properties que se encuentra en la ruta \\plugins\org.eclipse.jface.nl_es_0.2.0.v20080615043401\org\eclipse\jface\resource

Estos ficheros de propiedes contienen el tipo de fuentes que se utilizan en diferentes tipos de controles pertenecientes a la interfaz de usuario. Es en este fichero donde estará especificado el tipo de letra Sans Serif que tendremos que sustituir por un tipo de letra TrueType.

En nuestro caso el cambio realizado es el siguiente:

org.eclipse.jface.bannerfont.0=Tahoma-bold-8

org.eclipse.jface.headerfont.0=Tahoma-bold-12

Parchear Windows 7 para que utilice las fuentes 120DPI.

Parchear Windows 7 implica tocar el registro. Esta opción, aunque válida, no es recomendable pues lo que se hace es trampear el sistema. La trampa consiste en que para determinados casos, en vez de utilizar el fichero de fuentes que debería utilizarse (96DPI), que es el correcto pero no está instalado, se utilice el fichero de fuentes incorrecto pero existente en el sistema (el de 120DPI).

Aún así, dejo aquí la solución por si alguien tiene prisa en sacar adelante su programa y no tiene tiempo de aplicar las soluciones anteriormente recomendadas.

Lo primero que hay que hacer es acceder al registro de Windows 7 utilizando la herramienta regedit.

Una vez dentro del editor del registro se busca la clave MS Sans Serif 8,10,12,14,18,24 que se encuentra en la ruta HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts\.

El truco es cambiar el valor existente en esa entrada, SSERIFF.FON por el valor SSERIFE.FON

is set to SSERIFF.FON on a system which started at 125% DPI. The setting is set to SSERIFE.FON on a system which started at 100% DPI. Notice that one character of the file name changes from F to E.

The actual font files used might be different on Windows systems for other languages or code pages. See the table below for the file names:

While we are fixing the MS Sans Serif font, we can also fix the MS Serif and Courier fonts. These are the Registry settings MS Serif 8,10,12,14,18,24 and Courier 10,12,15 values in the same registry key. See the table below for the file names:

To fix the system you need to change the settings to new file names (changing the appropriate letter from F to E) and reboot.

Note: The registry changes do not take effect until the system has been restarted. You MUST reboot after making the registry changes.

Below are the contents of Font Fix.reg file to make the changes for an English system:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts] «MS Sans Serif 8,10,12,14,18,24″=»SSERIFE.FON» «MS Serif 8,10,12,14,18,24″=»SERIFE.FON» «Courier 10,12,15″=»COURE.FON»

Links. Windows 7, bitmap fonts and Microsoft Dynamics GP