viernes, 26 de septiembre de 2008

Oracle: modo "Servidor Dedicado"

Para los "listillos" en Oracle, como yo. Es decir aquellos que no somos DBA sino que nuestra experiencia se basa más en Java, pero que nos ha tocado alguna vez configurar Oracle.

Y claro, es un mundo. Y claro, las opciones aparentemente más lógicas no son las mejores.

En concreto me ha pasado con la configuración de Shared/Dedicated Server. En las instrucciones de creación de base de datos dice lo siguiente:
  • Modo Servidor Dedicado: "para cada conexión cliente la base de datos asignará un recurso exclusivo (...). Utilice este modo cuando el número total previsto de conexiones cliente sea pequeño o los cuando los clientes realicen solicitudes reiteradas y de larga duración a la base de datos. (...)"
  • Modo Servidor Compartido: "varias conexiones cliente comparten un pool de recursos (...). Utilice este modo cuando el número de usuarios que dan conectarse simultáneamente a la base de datos sea considerable a la vez que se utilizan eficazmente los recursos del sistema. (...)"
A priori, ¿cuál eligiríais? Pues no.

La cuestión es qué se considera "pequeño" en cuanto al número de conexiones. Y qué hardware tenemos. Y si el servidor Oracle compite por recursos con otros procesos importantes en la misma máquina. Y cómo se conectan las aplicaciones a la base de datos.

En resumidas cuentas, el modo compartido es un pool de conexiones. Pero nuestras aplicaciones (Java o lo que sea) ya gestionan las conexiones a través de uno o varios pooles por lo que lo único que estamos haciendo es anidar pooles. O lo que es lo mismo, en realidad en un escenario como el mío estoy tirando recursos y rendimiento a la basura. Cada shared server consume unos 20 megas de memoria adicional y, al fin y al cabo, termina abiendo conexiones reales dedicadas, claro.

Esquema del modo dedicado (Dedicated):

Esqueña del modo compartido (Shared Servers):


Por regla general podemos considerar que si vamos a tener menos de 500-600 sesiones abiertas y además hay pooles de conexiones en los servidores de aplicaciones cliente, se use el Modo Dedicado. En caso de un volumen mucho mayor el modo compartido.

¿Y cómo cambiar de un modo compartido a uno dedicado?. En Oracle 10g y superiores:
$ sqlplus system as sys dba
SQL> alter system set processes=400 scope=spfile;
SQL> alter system reset sessions scope=spfile;
SQL> alter system set shared_servers=0 scope=spfile;
SQL> alter system set max_shared_servers=0 scope=spfile;
SQL> alter system reset dispatchers scope=spfile;
Donde dice "400", establézcase el valor que corresponda. Si no se establece valor para sessions, el sistema lo tomará de la siguiente fórmula: sessions = (processes * 1.1) + 5.

Puesto que estos valores son estáticos, debe reiniciarse la instancia para que tome su valor.

¿Y cómo se consultan los valores actuales?:
SQL> show parameter [parametro]
P.D: Para los que conocen el init.ora y no los SPFILES, las cosas han cambiado, ahora los parámetros se establecen a través de estos comandos de sistema...

domingo, 21 de septiembre de 2008

6u6-p: Pues en Linux x64 peta!!!!!!!

[Actualizado el 8/11/2008: El problema radica en un bug en el Escape Analisys, para más información ver Identificación de bugs en la versión 6u6p y workaround ]

Actualización al post Java SE 6u6-p Performance Release - YA DISPONIBLE EN OTRAS PLATAFORMAS:

Al lanzar Glassfish, mientras se despliegan mis aplicaciones (gordas eso sí), aproximadamente en el 70% de las ocasiones se me ha producido un core con un correspondiente fichero de err_.log. Lo curioso es que en el 30% restante de las veces ya no se cae, aunque pase pruebas de stress... Lo he probado tanto en CentOS 5.1 sobre un Supermicro como en un Redhat ES sobre un Sun Fire x64 y en ambos ocurre lo mismo.


He reportado la incidencia y los ingenieros de Sun están en contacto conmigo par resolverla... pero vamos, me ha dejado el asunto un poco frío porque en la propia web de Sun dice que la versión puede ser utilizada en producción y que puedes pedir soporte. Vamos, que en ningún momento tenía la sensación de que fuera a hacer de beta-tester, aunque lo hago bien a gusto. Digo esto como una crítica "suave", porque todos los del gremio estamos expuestos a estos fallos...

Pero nuestro gozo en un pozo de momento. Así que volvemos a la confortable versión 1.6.0_07...

martes, 16 de septiembre de 2008

Aceleradores hardware

[Nota: en este artículo hago publicidad de marcas y modelos que conozco, sin otro ánimo que el ilustrativo y en ningún caso quiere decir que alternativas de la competencia sean peores opciones].

Actualizado el 19/9/2008


Con los avances en paralelización y multithreading de los últimos años (aunque con un cierto estancamiento de la velocidad por core), actualmente los responsables de servicios podemos adquirir servidores muy potentes a un coste relativamente bajo si lo comparamos con años anteriores. Ejemplos como Supermicro dan opciones muy económicas para entornos de "no tan misión crítica", pero fabricantes como HP e incluso Sun dan opciones x64 tremendamente interesantes (donde sube el precio es en el soporte).

En cualquier caso, hay situaciones que requieren "algo más". Y me explico. Si tenemos un entorno web de mucha concurrencia y computacionalmente "denso" puede ser que con un crecimiento horizontal en granja no sea suficiente. O mejor dicho, para mi gusto hay otras opciones que no requieren incrementar el número de máquinas.

Me estoy refiriendo a los aceleradores hardware. Los principales usos son la aceleración de SSL (operaciones de criptografía simétrica y asimétrica específicas para comunicaciones), HSM (operaciones criptográficas de propósito general) y GZIP (para la compresión de contenidos como se menciona en el post Compresión HTTP). He visto en una gran entidad financiera, con mis propios ojos, "morirse" un pedazo de servidor cuando hacía las operaciones SSL en los procesadores de propósito general, creedme.

Es cierto que muchos balanceadores y otros appliance de red nos solucionan parte de esta problática, pero en aquellos casos en los que esto no es una opción (o en los que precisamente lo que estamos construyendo es un appliance o proxy inverso) lo que debemos es adquirir los elementos hardware aceleradores adecuados. Hoy en día las opciones son mucho más económicas y mucho más potentes que lo que mucha gente se piensa.

Algunas opciones que hay en el mercado y que yo he tenido la oportunidad de probar (y poner en producción) son:
  • nFast SSL Offload (de nCipher): Tarjeta de red PCI (10/100/1000) que realiza las funciones criptográficas tanto asimétricas como simétricas (esta segunda parte es relativamente novedoso) necesarias para dar servicio SSL. Lo interesante de esta tarjeta es que actúa como un proxy inverso interno. Es decir, el interfaz de red atiende mediante canal SSL pero nuestro software servidores lo configuramos para que escuche "en plano", por lo que su integración es limpia e inmediata, y compatible con cualquier software.
    • Rendimiento nominal: 10.000 transacciones SSL/TSL por segundo
    • Throughput: 300 MBit/sec Full Duplex
  • AHA363 (de Comtech AHA): Tarjeta PCIe aceleradora GZIP, la más rápida del mercado. Trae una API y un módulo para Apache (aunque pueden desarrollarse otros.
    • Throughput: 5 GBit/sec
  • nShield 500 F2 (de nCipher): HSM completo que implementa todos los algoritmos de criptografía simétrica y asimétrica (incluso curvas elípticas). No se trata sólo de acelerador sino que su uso principal es la securización de claves privadas. Dentro de toda la gama de velocidades y niveles de securización, esta es más que suficiente para la mayoría de los propósitos, pero hay otras muchas opciones.
    • Rendimiento nominal: 500 firmas RSA de 1024 bits por segundo.
¿Os imagináis un sistema de servidores frontales x64 con dos procesadores XEON Quadcore y que además incorpore estas tarjetas? Imbatible. Y sorprendentemente económico, en órdenes de magnitud los elementos que he enumerado anteriormente rondan unos PVP de 3000€, 1000€ y 5000€ respectivamente. Es decir, obviando el HSM estaríamos aproximadamente duplicando el coste de un servidor promedio de las características mencionadas. Por unos 8000-9000 € tendríamos este sistema que aceptaría una concurrencia salvaje.

Obviamente tiene también sus inconvenientes, y es que cada elemento hard adicional incrementa las posibilidades de fallo, por lo que hay que considerar spare units y todo lo que conlleva.

Por cierto, respecto a la aceleradora GZIP no sólo estoy hablando de usarlo en la capa de servidor web / frontal, sino que fácilmente podríamos adaptar las bibliotecas Java o C de compresión para que en nuestra aplicación también utilizáramos el hardware de aceleración, e incluso hacer un JDK adaptado...

En algunos casos, en realidad, no hace falta irse tan lejos. ¿Sabíais que muchas de las capacidades de nuestros procesadores modernos están infrautilizadas? Para algunos propósitos no hay mejor acelerador hardware que el procesador que ya tenemos. Tanto AMD como Intel tienen bibliotecas de alto rendimiento para operaciones de copia de arrays, matemáticas, otras útiles para compresión, cifrado, procesamiento multimedia, etc).

Estoy hablando de Intel Integrated Performance Primitives (IPP) y de AMD Performance Library (APL). Un colega mío utiliza IPP para tratamiento de señales y asegura que es una auténtica maravilla, de hecho lo definió como "los ingenieros de Intel van 20 años por delante nuestro".

Una de las cosas con las que algunas veces he "soñado despierto" es con que las JVM/JDK puedan estar adaptados a estos aceleradores y también utilizar esas bibliotecas de Intel y AMD. Incluso llegué a mantener una conversación con Henrik Ståhl (Product Manager de JRockit en el momento de la conversación) preguntándole/proponiéndole sobre algunas de esas especializaciones. No lo veía claro y además los costes de mantenimiento sería brutal.

Por cierto que no soy el único que lo ha pensado, como puede verse en este hilo: http://forums.java.net/jive/thread.jspa?messageID=224530.

Pero volviendo al mundo real y asumible, os aseguro que el uso de aceleración SSL es una prioridad y la aceleración GZIP una auténtica necesidad si tenemos una concurrencia tremenda (¿cómo lo hará Google Inc.? ¿con aceleradores hard con los procesadores genéricos de las nubes de servidores?)

P.D.1: No he nombrado aceleradoras de gráficos, o el uso de las GPUs porque es un mundo que desconozco y que no he necesitado...

P.D.2: Sólo he nombrado esas marcas y modelos porque son los que yo conozco / he tenido experiencia satisfactoria. Hay otros fabricantes como http://www.safenet-inc.com/ o http://www.indranetworks.com/ con soluciones probablemente igual de válidas que las yo nombro arriba...

Actualización 19/9/2008: En otra conversación reciente con Henrik Ståhl, me sorprendió diciéndome que el uso de código / bibliotecas específicas para cierto hardware no es algo que hayan descartado para JRockit, aunque sea complicado. Digo que me sorprende porque en la primera conversación fue bastante tajante sobre los problemas que supondría y dudaba de los beneficios, sin embargo ahora ha dejado la puerta abierta. A mi ego le gusta pensar que he podido servir de empujoncito/inspiración...

miércoles, 10 de septiembre de 2008

Glassfish V2: Performance Tuning, Tips & Tricks

[Nota octubre'08: Ver información complementaria en el post Tuning de motor de JSP en Glassfish: Configuración para entorno de producción ]

En la documentación oficial de Glassfish están bastante bien documentadas las opciones de rendimiento y optimización a varios niveles (a nivel de aplicación, de servidor de aplicaciones, de JVM y de parametrización de Sistemas Operativos): Este blog contiene información general muy interesante sobre rendimiento de Glassfish: Y en esta presentación hay una relación clara y concisa de puntos de optimización en Glassfish:
Elementos que contiene esa presentación, con mis anotaciones personales entre corchetes:
  • Tuning
    • Tuning básico a nivel de JVM [nada nuevo]
    • Tuning del Web Container [ojo que por defecto hay pocos threads y conexiones keep-alive]
    • Tuning del EJB Container [idem con los tamaños de los pooles]
    • Tuning de la configuración en alta disponibilidad [nada nuevo]
    • Tuning de Web Services y parseo de XML en general [muy interesante el uso de Woodstox, aunque aún no por defecto, creo que la integración todavía es experimental]
    • Recomendaciones generales [incluyendo la precompilación de JSPs, y deshabilitar todos aquellos elementos que no vayan a usarse]

  • Best practices
    • ... (mejor leer la PPT)
Es cierto que hay que tener mucho cuidado con tirar de PPTs en lugar de estudiar durante semanas, pero se agradecen este tipo de resúmenes ejecutivos, la verdad!

[Nota octubre'08: Ver información complementaria en el post Tuning de motor de JSP en Glassfish: Configuración para entorno de producción ]

sábado, 6 de septiembre de 2008

Copy-on-write optimization for StringBuilder and StringBuffer (II)

Continuación sobre Copy-on-write optimization for StringBuilder and StringBuffer.

Bien, parece que sí hay un bug en la Bug Database (no fui capaz de encontrarlo), y sobre el que se hizo un montón de investigación y pruebas, sobre JDK 1.5. Para más información, consultar http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6219959. Como se ve el bug se cerró como "Not fixed"a principios de 2006.

Las explicaciones para el cambio de estrategia de copy-on-write a always-write son, resumidamente:
  • Cuando se derivaban Strings desde StringBuffers en JDK 1.4, había un crecimiento importante en el consumo de memoria en los Strings. Si tengo un StringBuilder con tamaño de buffer N y el String final sólo ocupa N/2 posiciones, la estrategia de compartir el buffer hace que el String ocupe el doble de memoria de lo que debería, mientras que la nueva estrategia lo ajusta.
  • Aparte de esto, está el molesto tema de la inmutabilidad de los Strings. Si se hiciera mal uso de un StringBuilder (ojo, el problema no se daría en StringBuffer), podría darse el caso durante un pequeño lapso de tiempo de que de que un thread esté leyendo un String mientras que otro esté cambiando su contenido porque aún no se haya enterado de la compartición. Casi imposible en la práctica pero teóricamente posible, así que...

Queda el consuelo, leyendo la descripción del bug, de que los ingenieros de Sun pasaron muchas horas con el tema, que cualquier posibilidad que a mi se me iba ocurriendo ya la han considerado (gracioso, en el bug va diciendo "uno podría argumentar que...", "también podría pensarse en...", justo lo que yo había deliverado :-) ).

Y queda el consuelo de que tanto en el foro como el en bug se llega a la conclusión de que un escape analisis sería una solución válida para que Hotspot decidiera hacer la optimización cuando una regiiónd e código sólo es alcanzada por un thread a la vez. Otra cosa es si el esfuerzo merece la pena, claro...

Tengo una idea cojonuda en esta línea. Voy a darle unas vueltas y a proponerla. Tanto en este blog como en el foro de rendimiento.

viernes, 5 de septiembre de 2008

Copy-on-write optimization for StringBuilder and StringBuffer

Hoy he publicado mi primer post en el foro "General performance Discussion" @java.net:

http://forums.java.net/jive/thread.jspa?messageID=297309

Forums @ java.net
Pego directamente (en inglés, me ha costado lo mío, je je):
Hello everybody.

The old 1.4 version of StringBuffer had a very nice implementation of a "copy-on-write" (COW), [as have the C++ String and the .NET StringBuilder, I think]. In few words: when the toString() method is called, it doesn't copy the char array to the String, but shares it with the String and marks as "shared" inside; and if there are future call to insert or remove or others in the "immutable" section of the char array, then creates a copy of the array and goes on (so the String keep immutable and the StringB can mute.

For some reason, this changed in JDK 1.5, becoming in a "always copy" strategy. Why? Haven't find it. I have only found the forum entry dated in 2005:
http://forums.java.net/jive/thread.jspa?messageID=29032.

I don't understand what kind of concurrency problem that the COW approximation has. Can someone put the light on me?

For testing, I have hacked AbstractBuilder, StringBuilder and StringBuffer with the COW hack. And in a microbenchmark there is a significant boost in both cases, also NetBeans, Glassfish, my J2EE apps and so on worked great with this patch. Sorry but no deep multithreading testing...

Why not reintroducing it in JDK 7? No API changes, cheap change, and a good boost.

Salvo que tenga unos problemas rarísimos que mi corta mente no llega a alcanzar, no veo por qué no... al fin y al cabo StringBuilder es thread-unsafe de por si, y StringBuffer... bueno, si funcionaba el COW en versiones anteriores del JDK no veo la diferencia (a no ser que no fuera realmente thread-safe, claro :-)

Por espacio, no pego el código de AbstractBuilder, StringBuilder y StringBuffer que he tocado, es algo distinto al 1.4 pero el concepto es el mismo...

Hilos (para el que tenga interés en los detalles concretos, de momento podéis revisar ambos hilos): Actualización - 05/09/2008:
Parece más un problema de consumo de memoria que de sincronización. Entiendo perfectamente el tema (puede verse en la Bug Database, bugs 4259569, 4724129, 4524848, 4910256), pero es una auténtica pena por el acelerón que supondría. Así que en el foro he propuesto combinar esta opción con -XX:+AggressiveOpts. Seguremos informando...


lunes, 1 de septiembre de 2008

¿Funcionan las optimizaciones sobre el modelo de threading?

http://www.infoq.com/articles/java-threading-optimizations-p1

Interesantísimo artículo, que explica varias de las opciones de arranque de la JVM que yo recomendaba en el post JVM tuning: Parámetros de lanzamiento de JVM: Sun Hotspot, complementando así la información que publiqué en el post Allocation, deallocation and escape analysis for Java . Trata los siguientes conceptos:
  • Escape analysis - lock elision explained
  • Biased locking explained
  • Lock coarsening explained
  • Adaptive spinning explained
Adicionalmente presenta los resultados de un benchmarking hecho por él mismo probando combinaciones de varias de estas opciones y comparando el rendimiento de StringBuffer vs StringBuilder en ellas. Si la magia existiera, los tiempos del StringBuffer deberían tender a los del StringBuilder al aplicar todas las optimizaciones. Sus resultados:

Mis resultados en Linux x64 con 2xXEONx4Cores:

  • Son similares a estos en cuanto a los parámetros que más contribuyen al rendimiento y en cuanto a que "la magia no existe: usa versiones no sincronizadas de las clases!". Nota: las pruebas de rendimiento sobre varios núcleos y/o varios procesadores son muy distintas que en máquinas con un sólo núcleo, donde no hay contención entre threads "reales".
  • Curiosamente, en mis pruebas con distintas versiones del JDK (1.5, 1.6.0_07, 1.6.0_06-6p, y JRockit) he visto cómo el rendimiento en la "Performance Release 6" se ha incrementado drásticamente en el uso de StringBuilders frente a la edición "normal" de Java 6 (que por cieto es más lenta que JDK 1.5), pero no tanto de StringBuffers. Y también que los resultados de JRockit en ambos casos eran los mismos, es decir que JRockit sí que optimiza correctamente cuando no hay contención posible y Hotspot no del todo...