Recientemente, a principios de Marzo, realice una actualización de PHP 7.2 a PHP 7.3. Sin embargo, lo que iba a ser una actualización sin problemas, pronto comenzó a volverse más complicado.

Los errores SIGSEGV en PHP aparecen una mañana

Durante unos días libres que tuve, realice una actualización de PHP desde 7.2.12 (aproximadamente) a la ultima versión disponible de PHP: 7.3.1

Todo salio bien en ese momento. Incluso las cosas funcionaban sin problemas, pero eso cambiaría a la mañana siguiente.

Fue entonces cuando este sitio web me arrojo un error 503. Así como otros más en esta VPS corriendo ubuntu.

Al revisar en los archivos de errores, en busca de alguna causa, solo encontraba lo siguiente:

(104)Connection reset by peer: [client XX.XX.XX.XX:XXXX] AH01075: Error dispatching request to : 

AH01067: Failed to read FastCGI header

Al mirar más de cerca, resulto que Apache servia contenido estático sin problemas. Solo las páginas generadas por PHP mostraban el error.

Cuando revise en los registros de PHP, la siguiente línea aparecía múltiples veces:

WARNING: [pool XXXXX] child XXXX exited on signal 11 (SIGSEGV - core dumped) after 30.977656 seconds from start

Este error de SIGSEGV en PHP significaba que había sucedido una Violación de Acceso de memoria (segfault o segmentation fault) por parte de PHP.

¿Cómo era esto posible? ¿Qué lo estaba causando?

Una de las soluciones temporales que encontré fue el usar el siguiente comando:

systemctl restart php7.3-fpm

Pero esta era una solución temporal. Ya que al poco tiempo el problema volvía a suceder. En algunos casos tan pronto como a los pocos segundos.

Esto se estaba volviendo una pesadilla.

Apache2, prefork y el modulo PHP7.3: ¿Origen del problema?

Durante mi investigación, detecte algo que pase por alto cuando actualice PHP a su versión 7.3: Me había agregado un nuevo módulo y cambiado el modo MPM de Apache.

El modo lo podemos ver con el siguiente comando en ubuntu:

apache2ctl -V

¿Eso explicaba el problema?

De lo primero que me percate es que ese nuevo módulo, llamado solamente «PHP7.3», necesitaba que Apache2 corriera en modo Prefork.

No entendí por que de este movimiento, pero no era el cual había configurado en el servidor: Event.

Por lo cual procedí a desactivar PHP7.3 y cambiar Prefork por Event, ejecutando lo siguiente:

sudo a2dismod php7.3
sudo a2dismod mpm_prefork
sudo a2enmod mpm_event
systemctl restart apache2
systemctl restart php7.3-fpm

De lo primero que me pude percatar, es que los errores de SIGSEGV en PHP bajaron dramáticamente con esto.

Aunque pronto descubriría que estos estaban lejos de desaparecer.

El error SIGSEGV en PHP da tregua, pero no por mucho

PHP 7.3 funciono de forma normal por algunos días. Pero eventualmente el error volvió a aparecer.

En los registros volvía a ver la señal 11 de SIGSEGV en PHP, lo cual me indicó que el problema tenia muchas posibilidades de seguir apareciendo.

Aunque era menos común, esto significaba que podía suceder en cualquier momento.

Buscando más a fondo, encontré quizá lo más profundo del origen del problema:

segfault at 6c6f4320 ip b4b92b37 sp bfe93df0 error 4 in opcache.so[b4b82000+6d000]

Por fortuna, comencé a notar que no era el único con este problema. Usuarios del panel Plesk también reportaron este problema. E incluso dicha empresa no está recomendando PHP7.3 por el momento.

Lo cual, parece indicar que no hay una solución definitiva por ahora.

Entonces, ¿Cómo solucionar las caídas de PHP?

Como comenté antes, PHP constantemente arroja un error segfault o SIGSEGV el cual interrumpe la ejecución de cualquier recurso dinámico.

Sin embargo, esto se soluciona cuando se reinicia el servicio. Hacerlo manualmente no es una solución aceptable. Y crear un cronjob no me parece una buena idea.

Pero hay alternativas que ya ofrece PHP de forma nativa.

Por ejemplo, nosotros podemos editar el archivo php-fpm.conf (ya que es el modo FPM el cual fallaba para mi) y configurar lo siguiente:

/etc/php/7.3/fpm/php-fpm.conf :
emergency_restart_threshold = 3
emergency_restart_interval = 1h
process_control_timeout = 10s

Con esto, hacemos que PHP este al pendiente por errores. Y cuando sucedan 3 errores en una hora, se reiniciará automáticamente.

De esta forma, el servicio se restablecerá de forma automática sin necesitar nuestra intervención.

Estos valores pueden ser fácilmente cambiados de acuerdo a tus propias necesidades. Solamente recuerda reiniciar el servicio de php-fpm una vez hagas cambios.

Para concluir

Si bien actualmente PHP7.3 parece tener problemas con su sistema de cache interno, con las correcciones adecuadas es posible usarlo sin problemas.

Pero hay algo muy importante que resaltar. Por ahora es mejor el mantenerse en PHP7.2 o tener múltiples versiones instaladas si es posible.

Ya que, a diferencia de la versión más nueva, PHP7.2 está mucho más maduro y este tipo de problemas son mucho más raros.

En mi caso, todavía sigo buscando que es lo que causa el error de SIGSEGV en PHP 7.3, y aunque sospecho que puede causarlo… no tengo una solución definitiva.

Lo que si, espero que esta pequeña guía le sea de utilidad a alguien. Ya que encontrar una solución, aunque parcial, fue una búsqueda de varios días.