2011-11-18 10 views
6

Al igual que con cualquier problema de administración de memoria, esta es una historia larga, por lo tanto, con correa.Confusing Tomcat Perfil de memoria de sesión persistente

Tenemos una aplicación que ha estado sufriendo algunos problemas de administración de memoria, así que he estado tratando de perfilar la aplicación para tener una idea de dónde radica el problema. Vi este hilo el día de hoy:

Tomcat Session Eviction to Avoid OutOfMemoryError

... que parece hacer lo mismo con lo que estaba viendo en el generador de perfiles. Básicamente, si presiono la aplicación con un grupo de usuarios con Jmeter, se mantendría en la memoria del montón durante mucho tiempo, hasta que las sesiones comenzaran a expirar. Sin embargo, a diferencia del póster en ese hilo, tengo la fuente y la opción de intentar implementar sesiones de estado persistentes con Tomcat, que es lo que he intentado hacer hoy, con un éxito limitado. Creo que es una configuración que me falta. Esto es lo que tengo en context.xml:

<Manager className='org.apache.catalina.session.PersistentManager' 
       saveOnRestart='false' 
       maxActiveSessions='5' 
       minIdelSwap='0' 
       maxIdleSwap='1' 
       maxInactiveInterval='600' 
       maxIdleBackup='0'> 
    <Store className='org.apache.catalina.session.FileStore'/> 
    </Manager> 

Y en web.xml tengo esto:

<session-config> 
    <session-timeout> 
     10 
    </session-timeout> 
</session-config> 

Tu lugar ideal para las sesiones de tiempo de espera de una hora, pero para propósitos de prueba esta está bien. Ahora, después de haber jugado un poco con algunas cosas y, finalmente, llegar a estos ajustes, estoy viendo la aplicación en el perfilador y esto es lo que estoy viendo:

enter image description here

Como se puede ver en la imagen, no tengo poner algunas anotaciones Es la parte rodeada alrededor del signo de interrogación que realmente no entiendo más que cualquier otra cosa. Puede ver que estoy usando el botón 'Realizar CG' de Jconsole en algunos puntos diferentes, y puede ver la parte en el gráfico donde estoy llegando a la aplicación con muchos clientes con Jmeter.

Si recuerdo correctamente (tendría que volver atrás y realmente documentarlo para estar seguro), antes de implementar el estado persistente, el botón GC no haría tanto como para borrar el montón. Lo extraño aquí es que parece que tengo que ejecutar manualmente GC para este estado persistente para realmente ayudar con cualquier cosa.

Como alternativa, ¿se trata simplemente de un escenario de pérdida de memoria normal? Hoy temprano, tomé un volcado de pila y lo cargué en la herramienta Eclipse Memory Analyzer, y usé la función 'Detectar fuga', y todo lo que hice fue reforzar la teoría de que este es un problema de tamaño de sesión; la única filtración que detectó fue java.util.concurrent.ConcurrentHashMap $ Segment que me llevó a este hilo Memory Fully utilized by Java ConcurrentHashMap (under Tomcat)

lo que me hace pensar que no es la aplicación la que realmente está goteando.

Otros detalles relevantes: - Ejecutar/probar esto en mi máquina local por el momento. De ahí provienen todos estos resultados. - El uso de Tomcat 6 - Esta es una aplicación JSF2.0 - He añadido la propiedad del sistema -Dorg.apache.catalina.STRICT_SERVLET_COMPLIANCE = true según la documentación de Tomcat

lo tanto, creo que hay varias preguntas aquí : 1. ¿Tengo esto configurado correctamente? 2. ¿Hay una pérdida de memoria? 3. ¿Qué está pasando en este perfil de memoria? 4. ¿Es (relativamente) normal?

Gracias de antemano.

ACTUALIZACIÓN

tanto, he intentado consejos de Sean, y encontré algunas nuevas cosas interesantes.

El oyente de sesión funciona muy bien y ha sido fundamental para analizar este escenario. Otra cosa, que olvidé mencionar es que la carga de la aplicación solo se ve realmente confundida por una sola página, que alcanza una complejidad funcional en una proporción casi cómica. Entonces, en las pruebas, a veces intento golpear esa página, y otras veces la evito. Así que en mi próxima ronda de pruebas, esta vez usando el oyente de la sesión encontré lo siguiente:

1) Golpeé la aplicación con varias docenas de clientes, simplemente visitando una página simple. Noté que todas las sesiones se lanzaron como se esperaba después del límite de tiempo especificado, y se lanzó la memoria. Lo mismo funciona perfectamente con un número trivial de clientes, para el caso complejo, accediendo a la página 'grande'.

2) A continuación, traté de golpear la aplicación con el caso de uso complejo, con varias docenas de clientes. Esta vez, se iniciaron varias docenas de sesiones más de lo esperado. Parecía que cada cliente iniciaba entre una y tres sesiones. Después del tiempo de caducidad de la sesión, se liberó un poco de memoria, pero según el oyente de la sesión, solo se destruyó alrededor de un tercio de las sesiones. Contradiciendo que, sin embargo, la carpeta que en realidad contiene los datos de las sesiones está vacía. La mayor parte de la memoria que se usó se retendrá también. Pero, después de exactamente una hora de ejecutar la prueba de estrés, el recolector de basura se ejecuta y todo vuelve a la normalidad.

Por lo tanto, las preguntas de seguimiento incluyen:

1) ¿Por qué podrían las sesiones manejarse adecuadamente en el caso sencillo, pero cuando las cosas se ponen mucha memoria, dejan de ser administrado correctamente? ¿El controlador de sesión está informando incorrectamente sobre algo, o usar JMeter impacta de alguna manera?

2) ¿Por qué el recolector de basura espera una hora para correr? ¿Hay alguna configuración de sistema que obligue a que el recolector de basura DEBE ejecutarse dentro de un marco de tiempo dado, o si me falta alguna configuración de configuración?

Gracias de nuevo por la asistencia continua.

ACTUALIZACIÓN 2

Sólo una nota rápida: jugar con esta un poco más, descubrí la razón por la que estaba recibiendo diferentes informes sobre el número de sesiones en vivo es debido al hecho de que estoy usando persistente sesión; si lo desactivo, todo funciona como se espera. De hecho, dice en la página de Tomcat para sesión persistente, que es una característica experimental. Debe estar llamando a eventos de sesiones que el oyente está retomando, cuando uno esperaría atípicamente que lo hiciera.

Respuesta

5

Vamos a tratar y hacer frente a las preguntas lo mejor que pueda

  1. Para su configuración, se ve bien para mí en el papel. Si desea asegurarse de que sus sesiones se crean y destruyen correctamente, le conviene configurar un oyente de sesión para que inicie sesión o muestre una lista de sesiones abiertas. Aquí hay un enlace a un example

  2. No creo que haya una pérdida de memoria. Los GC incrementales se están ejecutando. parece que se está promoviendo mucha memoria en la vieja generación. Pero una vez que su aplicación puede ejecutar un GC completo, la memoria vuelve a la normalidad.Si necesita que la sesión de sus usuarios tenga una gran cantidad de datos almacenados en ellos, la memoria será su compensación. Siempre y cuando destruyas los datos una vez que cierren la sesión/se agote el tiempo de espera, la memoria debería estar bien a la larga. Su área de pregunta (???) sería el área gris donde sus sesiones todavía están activas para que los datos almacenados en ellos se mantengan, posiblemente promovidos a la generación anterior en este punto. Una vez que la memoria se promueve a la vieja generación, necesita un GC completo para limpiarla. Hacer clic en el botón hizo eso. La aplicación finalmente habría programado el GC completo.

  3. Creo # 2 ayuda a responder a esta

  4. de que se ve normal para una prueba de esfuerzo. Intente ejecutarlo nuevamente sin presionar el botón Realizar GC. Vea si la memoria volverá a bajar por sí misma. Tenga en cuenta que el recolector de basura hará el GC completo cuando sienta que debería hacerlo. Para borrar el generador anterior, se requiere una pausa para que el GC no realice esa acción a menos que sienta que no tiene suficientes recursos para administrar la aplicación correctamente.

Algunas otras cosas que puede hacer para futuras pruebas. Tome nota del uso del montón entre la generación joven y la generación anterior del montón. En la captura de pantalla podemos ver que hay 872 mb de heap comprometidos, por lo que tener un desglose de dónde se encuentra la memoria durante las pruebas de carga ayudará a identificar correctamente dónde se guarda el montón.

De manera similar, considere activar el registro verbose GC para que pueda obtener un informe del desglose del montón. hay muchas herramientas para ayudarlo a graficar el registro del GC para que no tenga que leer el registro manualmente. Esto también se puede registrar en un archivo (-Xloggc: archivo) si no desea que se envíe a stdout.

Si el tamaño de la sesión se está volviendo demasiado grande para administrar, es posible que desee descargar esa memoria en otro lugar. Algunos ejemplos pueden ser utilizar BigMemory, DB Persistance o alguna otra forma de reducir el tamaño de las sesiones.

+0

Sean, gracias por la explicación en profundidad. Lamento no haber contactado antes. Básicamente publiqué y me desconecté durante el fin de semana. De todos modos, acepté su respuesta, pero también publiqué algunas preguntas de seguimiento, si tiene tiempo para ayudar más. Si no, sus consejos ya me han ayudado a seguir adelante, y su conclusión de que no hay pérdida de memoria me ha dado tranquilidad. – user470714

0

no veo donde cualquiera señaló su error tipográfico:

minIdelSwap='0' 

No estoy seguro de que eso sea útil para nadie, pero sin duda que el PersistenceManager comportarse de manera diferente de lo que cabría esperar que lo haga.

Cuestiones relacionadas