Aproximadamente una vez a la semana, pero a veces incluso un par de veces al día después de funcionar bien durante días, mis instancias de EC2 dejan de responder. Los gráficos de memoria de Munin cuentan una historia bastante sencilla: la memoria asignada a las "aplicaciones" comienza a crecer y no se detiene hasta que el intercambio se utiliza por completo y la instancia se pone de rodillas. Otro gráfico personalizado muestra que el proceso en constante crecimiento es apache2.
Ejecuto una configuración estándar de Apache prefork con mod_php y algunos scripts PHP. Como puede ver en el gráfico a continuación, sucede algo que activa los procesos apache2 para comenzar a consumir más y más memoria. El primer pico verde lo atrapé a tiempo y reinicié Apache antes de que las cosas se salieran de control. El segundo pico llegó un poco más lejos y la instancia tuvo que reiniciarse por completo.
Lo que me pregunto es cómo depurar esto mejor. A menos que configure PHP con FastCGI y lo ejecute en sus propios procesos, ¿cuál es una buena manera de averiguar si es Apache o una combinación de PHP y mi código lo que está causando el uso excesivo de memoria? ¿Qué pasos tomarían para rastrear este problema?
ACTUALIZACIÓN: pude rastrear la fuga después de involucrar strace, como Matt sugirió a continuación.
Después de encontrar un proceso apache2 que crecía gradual y continuamente en la memoria, agregué algunas llamadas más de error_log () a mi script PHP que imprimieron la cantidad total de RSS utilizada en varios puntos de su ejecución (usando la salida de ps). Sin embargo, eso resultó ser engañoso: si bien parecía que RSS saltó solo después de que mi script terminó de ejecutarse, la depuración posterior reveló que ese no era realmente el caso. ¡Ten cuidado!
Afortunadamente, todas esas llamadas error_log () resultaron ser útiles al final. Cuando encendí strace ( strace -p <pid> -tt -o trace.log -s 256
), vi que para cada solicitud, el proceso estaba asignando alrededor de 400k de memoria (busque la llamada al sistema 'brk' y reste el parámetro de la primera llamada de la última llamada; algunas generalmente vienen en una después de otro). Luego busqué la llamada al sistema 'write' más reciente que contenía mi mensaje error_log (), que me decía en qué punto del script se estaba asignando la memoria. Con unas pocas llamadas error_log () estratégicamente ubicadas para identificar la ubicación con mayor precisión, finalmente encontré al culpable.
La memoria estaba perdiendo cuando llamamos curl_exec () desde nuestro script PHP. Algunos códigos curl relacionados con el manejo de una conexión SSL están haciendo algo mal: la fuga desapareció cuando cambié a HTTP. El registro de cambios de Curl hace referencia a algunas pérdidas de memoria SSL que se solucionaron en 7.19.5 (estábamos en 7.18.2), así que lo intentaré a continuación.
Mientras tanto, estoy ejecutando con un MaxRequestsPerChild muy bajo que mantiene a Apache dentro de límites razonables. ¡Gracias a todos!