martes, julio 10, 2007

GC para tiempos bajos de respuesta (I)

martes, julio 10, 2007 por Martín

Hace unas semanas tuve que realizar un pequeño análisis de la recolección de basura en JRockit para llegar a una recomendacción de argumentos, políticas, etc. Voy a poner aquí algunas de las notas por si a alguno le resultan útiles, aunque la verdad es que muchos seguro que ya las conocéis de sobra.

Gran parte de este análisis está basado en la búsqueda de tiempos de respuesta bajos. En el caso de intentar optimizar un sistema para un máximo throughput, sería necesario realizar algunos cambios. Son notas genéricas en la medida de lo posible aunque mi análisis estaba orientado a JRockit.

  1. Preferir GC estático sobre dinámico: Algunas máquinas virtuales, como por ejemplo JRockit, tienen un modo de ejecución dinámico en la que van modificando los parámetros del algoritmo de recolección de basura en base al rendimiento de la aplicación. Son capaces de aumentar el tamaño del heap, disminuirlo, cambiar el tamaño de las generaciones o cambiar los valores de los diferentes parámetros según crean conveniente.

    El problema de esto es que con un algoritmo dinámico pierdes el control de la gestión de basura, y aunque la máquina virtual es realmente inteligente, en muchas ocasiones te desea restringir lo máximo posible la libertad del GC para tener la situación controlada.

    Este es el caso de los sistemas donde no se puede tolerar de ningún modo un tiempo de respuesta alto, ya que puede significar el incumplimiento de un SLA y como consecuencia una perdida económica importante.
  2. Establecer el máximo el mínimo del heap al mismo valor: De lo contrario, la máquina virtual estará gastando valiosos ciclos de CPU en alargar y encoger el tamaño del heap continuamente según considere conveniente. Nuevamente esto puede afectar al rendimiento de la aplicación e influir negativamente en los tiempos de respuesta.
  3. Asegurarse de que el tamaño del heap no es tan o más grande que la memoria física: En un servidor (o cualquier ordenador) siempre hay más procesos ejecutándose a parte de la máquina virtual. Estos procesos requerirán su espacio de memoria física. Si el tamaño del heap de la máquina virtual es demasiado grande entonces podemos caer una situación en la que nuestro servidor esté continuamente paginando porque no habrá suficiente memoria física para todos los procesos, o sólo para él si ha pedido demasiada memoria. Esto originará continuos accesos a memoria virtual para intercambiar páginas de memoria, lo que enlentecerá todo el sistema, disminuyendo drásticamente el rendimiento del mismo.
  4. Utilizar un algoritmo de recolección concurrente: Hoy por hoy la mayoría de máquinas virtuales te ofrecen la posibilidad de utilizar diferentes algoritmos según tus necesidades. Dos de los algoritmos más típicos son el concurrente, orientado a tiempos de respuesta bajos, y el paralelo orientado a conseguir un máximo throughput.

    En el algoritmo concurrente la recolección de basura se hace paralelamente a la ejecución de la aplicación, en pequeñas pausas que dan la impresión de que no hay recolección de basura. La desventaja es que se dedica constantemente tiempo de CPU para realizar esta labor.

    En un algoritmo paralelo, el recolector simplemente no realiza la recolección de basura hasta que no se llena por completo el heap. Una vez que el heap está completo, se para la ejecución de todos los hilos y se inicia una enorme recolección de basura dedicando todas las CPUs disponibles a esa tarea. Todas las CPUs realizan la recolección de modo paralelo.

    El problema de este último algoritmo para sistemas de respuesta baja es que la recolección puede ser enormemente costosa y detener el sistema por segundos o incluso minutos, lo que significa con toda seguridad romper SLAs que tengas marcados. Es por ello que un sistema como estos no puede recurrir a una recolección de este estilo que para por completo la ejecución del sistema.
  5. Optimizar el tamaño de la young generation:
  6. Los algoritmos orientados a una rápida respuesta suelen estar basados en generaciones. Normalmente hay dos generaciones, una joven (young generation, nursery en JRockit) en la que se alojan los objetos recientemente creados, y otra vieja (old generation) en la que se van guardando los objetos que permancen más tiempo en memoria. Las recolecciones de basura en la young generation suelen ser cortas y rápidas. Cuando la young generation se llena, se realiza una recolección, se vacia la generación y se mueven los objetos que deban quedar en memoria a la old generation. El tamaño de esta young generation es bastante importante. La idea es mantener su tamaño lo más grande que sea posible al tiempo que se mantiene el tiempo de recolección en un rango aceptable. Si la young generation es demasiado grande, las recolecciones serán más costosas y esto impactará en el rendimiento del sistema. Al mismo tiempo, estaremos dejando menos espacio disponible para la old generation, lo que eventualmente puede hacer que las recolecciones completas de todo el heap sean más frecuentes. Por el contrario, si el tamaño de la young generation es demasiado pequeño, no daremos tiempo a que los objetos se liberen, y la mayor parte serán promocionados rápidamente a la old generation, lo que hará que ésta última se llene rápidamente causando recolecciones completas de todo el heap. Es importante pues mantener el tamaño de la young generation en un punto equilibrado. Lo suficientemente grande para darle tiempo a los objetos a ser desreferenciados pero sin que sea demasiado costoso realizar una recolección de basura en ella.


Como he visto que este post me queda bastante largo he decidido dividirlo en dos. Muy pronto pondré la segunda parte. Mientras tanto si alguien quiere aportar algo... bievenenido sea.

comments

3 Respuestas a "GC para tiempos bajos de respuesta (I)"
jcesar dijo...
9:03

Estupendos apuntes! Me quedo con ganas de ver la segunda parte.

Un saludo.


Franciscano dijo...
11:51

La verdad es que el verano esta siendo de aupa aqui...

Por que no haces algun comentario sobre la escalada de Lua en el ultimo anho?

Saludos desde Norwich.
Alvaro.


Martín dijo...
19:16

Gracis jcesar.

Álvaro, es que no tengo ni idea de Lua :)