Mejorando lo presente
Relay | febrero 25, 2010Este es un post técnico que complementa al de cómo implementé el tema de NginX + PHP en FastCGI.
Desde siempre, dados varios bugs conocidos de php en cgi que, según la versión, hacían que los sockets fueran más o menos estables tenía un proceso en el cron del sistema que me reiniciaba el php (los sockets realmente) cada día a las 6:15 de la mañana.
A veces, cada X semanas, el php se quedaba colgado y lo reiniciábamos manualmente. NOTA: no es que el php se quedaba colgado, el tema radica en que el socket de escucha se quedaba tonto sin responder, los procesos de php seguían ejecutándose esperando cargas y peticiones (en estado suspendido). La solución al reiniciar, era que matando los procesos y rearrancando esa parte, el socket se creaba de nuevo y volvía a la normalidad.
Esto no se trata en casi ninguna web, exceptuando una: En el blog de Taragana.
Tras varios meses así, decidí implementar una mejor solución. Encontré una versión mejorada para Ubuntu (aunque yo uso Debian) de un script de arranque usando demonios. Tras esto, mejoraba 2 cosas: era más consistente el arranque (al poderlo poner en el arranque del sistema sin problemas) y se cargaba la configuración de php con más megas de RAM asignados (de la otra manera lo que pasaba era que se arrancaba el php en fcgi con valores por defecto (aunque le pasara por parámetro el fichero php.ini).
Estos scripts básicamente son dos: /etc/default/php-fastcgi (fichero de configuración) y el script de arranque.
Este cambio lo realicé a principios de enero y durante 2 semanas no dió ningún problema, tuve que comentar la linea de reinicio del cron porque no era necesario.
Pero tras eso, por alguna actualización o algo, la cosa fallaba como una escopeta de feria. Volví a poner el reinicio cada 2 días, pero ni eso… lo volví a poner a un día. Pero no bastaba…
La solución por probar era compilar el php-fm, pero se me antojaba demasiado complicado para dejar el sistema tal como lo tengo ahora, así que decidí investigar.
Primero pensé en ver si había alguna otra implementación de sockets que recibiera peticiones y pudiera ejecutar lo recibido usando el cliente normal de php de bash. Miré si había alguna manera de crear sockets desde 0 con php para este fin, pero no había nada sin tener que sumirme en decenas de varios de documentos de programación en C sin tener mucho tiempo.
Tras buscar, llegué hasta un blog que hablaba del tema. El auto se había programado un script en python que, básicamente, escaneaba por errores en el log del NginX cada 2 segundos sin impacto en el sistema. El que aquí os pongo simplemente tiene comentadas las lineas para enviar correo, dado que pasaba mal algunos parámetros al sendmail y se colgaba.
Básicamente, lo que hace es:
- Se ejecuta y se ‘demoniza’, así que se queda en el sistema.
- Escanea el
/var/log/nginx/error.log
cada 2 segundos, usando algo comotail -f
. - Si se encuentra en el log las cadenas “104: Connection reset by peer” o “111: Connection refused”,
- Ejecuta un
killall -9 php5-cgi (el binario se puede configurar)
- Ejecuta el script de arranque
/etc/init.d/php-fastcgi start
- Ejecuta un
Al usar el tail -f, se usa muy poca memoria y permite estar tranquilo… como mucho hay un downtime de varios segundos. Luego se arranca como si no hubiera pasado nada.
Para evitar que algo reviente el phpmonitor.py, he creado un script en bash ejecutado cada minuto via cron que simplemente mira si se está ejecutando el monitor. Si se ejecuta, sale; si no, lo ejecuta. La doble seguridad o doble chequeo es necesario.
Cosas a mejorar:
- En el script de python, podríamos usar el propio script de arranque para parar los procesos en lugar de hacer un kill directamente; o usar un simple restart…
- Aplicar una parte de la solución de Taragana: crear pools para cada aplicación, así no siempre se quedaría todo parado. Aunque eso implicaría modificar el script de python para discriminar entre dominios/aplicaciones y no reiniciar lo que no toca