Análisis de pérdida de memoria RM del subproceso Hadoop
Al analizar la memoria RM, encontramos que el 95,63% del espacio en la memoria RM está ocupado por 1603 RMNodeImpl.
Hay un conjunto de hash en RMNodeImpl que contiene más de 13w elementos. Como resultado, cada RMNodeImpl tiene aproximadamente 14M.
Este conjunto de hash contiene más de 140.000 contenedores completos.
¿Por qué no se publican tantos contenedores completados?
Cuando NM informa un latido, RMNodeImpl agregará contenedores no iniciados (es decir, completados) y faltantes a los contenedores completados. Al responder al latido, los contenedores en contenedoresToBeRemovedFromNM se eliminarán de los contenedores completados, y NM también eliminará los contenedores en contenedoresToBeRemovedFromNM.
Los contenedores en contenedoresToBeRemovedFromNM se obtienen del contenedor rmnodefinished impulsado por amevent. RMAppAttempt envió un contenedor rmnodeffinalizado arrastrado por un evento.
Cuando RMAppAttempt recibe el evento CONTAINER_FINISHED, determinará si el contenedor es AMContainer. Si no es un AMContainer, se agregará al conjunto de hash de justFinishedContainers. Cuando AM informa un latido, llama a rmappattempt. método pulljustfinished contenedores(). Intento de rma. pullJustFinishedcontainers() es un método importante para limpiar contenedores completos. En este método, primero se llama al método sendFinishedContainersToNM() para enviar los contenedores enfinishedContainersSentToAM a NM, es decir, la parte de los contenedores eliminados de los contenedores completados en RMNodeI. Luego transfiera los contenedores en justFinishedContainers afinishedContainersSentToAM. El propósito de esto es que AM decida si eliminar estos contenedores, no NM. En el siguiente latido, los contenedores enfinishedContainersSentToAM se enviarán nuevamente a NM.
En el método sendFinishedContainersToNM(), el nodeId y el containerId se obtendrán de FinishContainersSentToAM para construir rmnodefiniedcontainerbyamevent, y luego se borrará FinishContainersSentToAM.
Si AMContainer se completa, rmappattempt. Se llamará a AMcontainerfinished para limpiar el contenedor ocupado por am. Primero, obtenga NodeId y ContainerStatus del evento rmappattemptContainer Finishevent y agréguelos afinishedContainersSentToAM. Entonces, intentalo. Llame al método sendFinishamContainertonm para limpiar el contenedor.
El proceso básico es el siguiente (la línea roja está relacionada con el latido del corazón AM):
Considere este escenario: se acaba de agregar un contenedor normal a justFinishedContainers.
Este contenedor debe esperar el latido de AM antes de poder agregarse a FinishContainersSentToAM, y luego se puede limpiar cuando se repite el latido de AM o se limpia AMContainer. Si se cierra la sesión de AM después de ejecutarse en este momento, AM ya no informará latidos y los contenedores en justFinishedContainers nunca tendrán la oportunidad de transferirse a FinishContainersSentToAM, y AMContainer no limpiará esta parte de los contenedores durante la limpieza. Entonces, estos contenedores en los contenedores completados de RMNodeImpl no se borrarán, sino que permanecerán en la memoria de RM.
Hay otra pregunta. Si RMAppAttempt ya está en el estado final (FINISHED, KILLED, FAILED), cuando se reciba nuevamente el evento CONTAINER_FINISHED, el contenedor solo se agregará a justFinishedContainer sin limpiar AMContainer. También hará que AMContainer no pueda publicarse.
En tercer lugar, optimización del problema
La razón del problema es que los contenedores normales permanecen en la memoria después de agregarse a justFinishedContainer, porque la cancelación de AM es demasiado tarde para pasarse a FinishContainersSentToAM. Además, después de recibir el evento CONTAINER_FINISHED, el estado final de RMAppAttempt no limpió AMContainer, lo que provocó que RMNodeImpl ocupara demasiada memoria.
Plan de optimización: RMAppAttempt en el estado final limpia AMContainer después de recibir el evento CONTAINER_FINISHED y determina si justFinishedContainer está vacío al limpiar AMContainer. De lo contrario, pasará el NodeId y el ContainerId de justFinishedContainer afinishedContainersSentToAM y los enviará a NM.
4. Resultados de la optimización
-después de los contenedores completados: el registro impreso indica los contenedores restantes después de que los contenedores en contenedoresToBeRemovedFromNM se eliminen de los contenedores completados.
Antes de la optimización: después de varios latidos de NM, todavía hay contenedores que han completado tareas en RMNodeImpl de datanode1 y datanode2.
Después de la optimización: no hay ningún contenedor en los contenedores completados.