Segmentation fault en Apache

Después de una migración de sistema operativo de un servidor web y cuando parece que todo funciona, empiezas a ejecutar las últimas comprobaciones y te das cuenta de que Apache empieza a escupir errores de Segmentation fault o violaciones de segmento.

¿Como podríamos detectar un problema de Apache que en un entorno de pruebas funciona perfectamente pero cuando lo montamos en producción empieza a generar violaciones de segmento a pesar de que las webs funcionan
perfectamente?

Lo primero que deberemos hacer es examinar los logs para ver que nos cuentan al respecto:


[...]
[Mon Apr 13 11:40:04 2009] [notice] child pid 2519 exit signal Segmentation fault (11)
[Mon Apr 13 11:40:04 2009] [notice] child pid 2520 exit signal Segmentation fault (11)
[Mon Apr 13 11:40:04 2009] [notice] child pid 2521 exit signal Segmentation fault (11)
[Mon Apr 13 11:40:04 2009] [notice] child pid 2522 exit signal Segmentation fault (11)
[Mon Apr 13 11:40:04 2009] [notice] child pid 2523 exit signal Segmentation fault (11)
[Mon Apr 13 11:40:04 2009] [notice] child pid 2524 exit signal Segmentation fault (11)
[Mon Apr 13 11:40:04 2009] [notice] child pid 2525 exit signal Segmentation fault (11)
[Mon Apr 13 11:40:04 2009] [notice] child pid 2526 exit signal Segmentation fault (11)
[Mon Apr 13 11:40:04 2009] [notice] child pid 2527 exit signal Segmentation fault (11)
[Mon Apr 13 11:40:04 2009] [notice] child pid 2528 exit signal Segmentation fault (11)
[...]

A simple vista no nos proporcionan demasiada información por lo que tendremos que activar la opción coredumps en Apache añadiendo la siguiente línea en el fichero de configuración httpd.conf.

CoreDumpDirectory /tmp

Hecho esto reiniciamos Apache. Dado que el problema no ocurre siempre, tendremos que esperar un tiempo prudencial en función del tráfico de nuestro servidor web en el que pueden transcurrir desde segundos a un par de minutos. Pasado este tiempo deberiamos ver algo como esto:


[...]
[Mon Apr 13 11:31:25 2009] [notice] child pid 20010 exit signal Segmentation fault (11), possible coredump in /tmp
[Mon Apr 13 11:31:25 2009] [notice] child pid 20015 exit signal Segmentation fault (11), possible coredump in /tmp
[Mon Apr 13 11:31:25 2009] [notice] child pid 20019 exit signal Segmentation fault (11), possible coredump in /tmp
[Mon Apr 13 11:31:25 2009] [notice] child pid 20022 exit signal Segmentation fault (11), possible coredump in /tmp
[Mon Apr 13 11:31:26 2009] [notice] child pid 20003 exit signal Segmentation fault (11), possible coredump in /tmp
[Mon Apr 13 11:31:26 2009] [notice] child pid 20013 exit signal Segmentation fault (11), possible coredump in /tmp
[Mon Apr 13 11:31:26 2009] [notice] child pid 20020 exit signal Segmentation fault (11), possible coredump in /tmp
[..]

Al leer el log y si tenemos bien configurado el parámetro ulimit -c unlimited veremos los core.* en el directorio /tmp/

Nota importante: Si no queremos llenar o provocar contención en el disco duro hay que acordarse de desactivar la opción coredumps

Ahora analizaremos los archivos core.* para ver qué información nos proporcionan:


# gdb /usr/local/apache2/bin/httpd core.25582
GNU gdb Fedora (6.8-27.el5)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu"...


warning: Can't read pathname for load map: Input/output error.
Reading symbols from /usr/lib64/libz.so.1...done.
Loaded symbols for /usr/lib64/libz.so.1
Reading symbols from /lib64/libm.so.6...done.
Loaded symbols for /lib64/libm.so.6
Reading symbols from /var/www/html/usr/local/apache2/lib/libaprutil-1.so.0...done.
Loaded symbols for /usr/local/apache2/lib/libaprutil-1.so.0
Reading symbols from /var/www/html/usr/local/apache2/lib/libexpat.so.0...done.
Loaded symbols for /usr/local/apache2/lib/libexpat.so.0
Reading symbols from /var/www/html/usr/local/apache2/lib/libapr-1.so.0...done.
Loaded symbols for /usr/local/apache2/lib/libapr-1.so.0
Reading symbols from /lib64/libuuid.so.1...done.
Loaded symbols for /lib64/libuuid.so.1
Reading symbols from /lib64/librt.so.1...done.
Loaded symbols for /lib64/librt.so.1
Reading symbols from /lib64/libcrypt.so.1...done.
Loaded symbols for /lib64/libcrypt.so.1
Reading symbols from /lib64/libpthread.so.0...done.
Loaded symbols for /lib64/libpthread.so.0
Reading symbols from /lib64/libdl.so.2...done.
Loaded symbols for /lib64/libdl.so.2
Reading symbols from /lib64/libc.so.6...done.
Loaded symbols for /lib64/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
Reading symbols from /lib64/libnss_files.so.2...done.
Loaded symbols for /lib64/libnss_files.so.2
Reading symbols from /var/www/html/usr/local/apache2/modules/mod_proxy.so...done.
Loaded symbols for /usr/local/apache2/modules/mod_proxy.so
Reading symbols from /var/www/html/usr/local/apache2/modules/mod_proxy_http.so...done.
Loaded symbols for /usr/local/apache2/modules/mod_proxy_http.so
Reading symbols from /var/www/html/usr/local/apache2/modules/mod_ssl.so...done.
Loaded symbols for /usr/local/apache2/modules/mod_ssl.so
Reading symbols from /lib64/libssl.so.6...done.
Loaded symbols for /lib64/libssl.so.6
Reading symbols from /lib64/libcrypto.so.6...done.
Loaded symbols for /lib64/libcrypto.so.6
Reading symbols from /usr/lib64/libgssapi_krb5.so.2...done.
Loaded symbols for /usr/lib64/libgssapi_krb5.so.2
Reading symbols from /usr/lib64/libkrb5.so.3...done.
Loaded symbols for /usr/lib64/libkrb5.so.3
Reading symbols from /lib64/libcom_err.so.2...done.
Loaded symbols for /lib64/libcom_err.so.2
Reading symbols from /usr/lib64/libk5crypto.so.3...done.
Loaded symbols for /usr/lib64/libk5crypto.so.3
Reading symbols from /usr/lib64/libkrb5support.so.0...done.
Loaded symbols for /usr/lib64/libkrb5support.so.0
Reading symbols from /lib64/libkeyutils.so.1...done.
Loaded symbols for /lib64/libkeyutils.so.1
Reading symbols from /lib64/libresolv.so.2...done.
Loaded symbols for /lib64/libresolv.so.2
Reading symbols from /lib64/libselinux.so.1...done.
Loaded symbols for /lib64/libselinux.so.1
Reading symbols from /lib64/libsepol.so.1...done.
Loaded symbols for /lib64/libsepol.so.1
Reading symbols from /var/www/html/usr/local/apache2/modules/mod_info.so...done.
Loaded symbols for /usr/local/apache2/modules/mod_info.so
Reading symbols from /var/www/html/usr/local/apache2/modules/mod_chroot.so...done.
Loaded symbols for /usr/local/apache2/modules/mod_chroot.so
Reading symbols from /var/www/html/usr/local/apache2/modules/libphp5.so...done.
Loaded symbols for /usr/local/apache2/modules/libphp5.so
Reading symbols from /usr/lib64/mysql/libmysqlclient.so.15...done.
Loaded symbols for /usr/lib64/mysql/libmysqlclient.so.15
Reading symbols from /usr/lib64/libmcrypt.so.4...done.
Loaded symbols for /usr/lib64/libmcrypt.so.4
Reading symbols from /usr/lib64/libltdl.so.3...done.
Loaded symbols for /usr/lib64/libltdl.so.3
Reading symbols from /usr/lib64/libfreetype.so.6...done.
Loaded symbols for /usr/lib64/libfreetype.so.6
Reading symbols from /usr/lib64/libX11.so.6...done.
Loaded symbols for /usr/lib64/libX11.so.6
Reading symbols from /usr/lib64/libXpm.so.4...done.
Loaded symbols for /usr/lib64/libXpm.so.4
Reading symbols from /usr/lib64/libpng12.so.0...done.
Loaded symbols for /usr/lib64/libpng12.so.0
Reading symbols from /usr/lib64/libjpeg.so.62...done.
Loaded symbols for /usr/lib64/libjpeg.so.62
Reading symbols from /usr/lib64/libcurl.so.3...done.
Loaded symbols for /usr/lib64/libcurl.so.3
Reading symbols from /lib64/libnsl.so.1...done.
Loaded symbols for /lib64/libnsl.so.1
Reading symbols from /usr/lib64/libxml2.so.2...done.
Loaded symbols for /usr/lib64/libxml2.so.2
Reading symbols from /usr/lib64/libidn.so.11...done.
Loaded symbols for /usr/lib64/libidn.so.11
Reading symbols from /usr/lib64/libXau.so.6...done.
Loaded symbols for /usr/lib64/libXau.so.6
Reading symbols from /usr/lib64/libXdmcp.so.6...done.
Loaded symbols for /usr/lib64/libXdmcp.so.6
Core was generated by `/usr/local/apache2/bin/httpd -k start'.
Program terminated with signal 11, Segmentation fault.
[New process 25582]
#0 apr_pollset_add (pollset=0x0, descriptor=0x7fff51ab15a0) at poll/unix/epoll.c:150
150 if (pollset->flags & APR_POLLSET_NOCOPY) {
(gdb)

Hemos encontrado el posible error en #0 apr_pollset_add (pollset=0x0, descriptor=0x7fff51ab15a0) at poll/unix/epoll.c:150

Esto ya es otra cosa. En Unix las aplicaciones necesitan de llamadas al sistema para que se les notifique cuándo hay tráfico en un socket con el objetivo de recibir un aviso y procesar dicho trafico. Hay varias llamadas para este fin como, por ejemplo, poll y epoll. Estas últimas son mas rápidas y existe un parámetro en el kernel que define cuántas instancias se pueden usar por cada UID:

# cat /proc/sys/fs/epoll/max_user_instances
128

Por defecto es de 128, pero dado que nuestro servidor Apache tiene unos requerimientos mayores, necesitamos incrementar este valor hasta , por ejemplo, 1024 que podria ser un número razonable:

# echo "fs.epoll.max_user_instances = 1024">>/etc/sysctl.conf
# sysctl -p
# cat /proc/sys/fs/epoll/max_user_instances
1024

Cambiado el valor reiniciamos Apache y observamos los logs durante un tiempo para ver si el problema ha
sido solucionado o por el contrario hay que ajustar mejor el valor.

Aunque este artículo hace referencia a Apache, este mismo problema se puede dar en otro tipo de aplicaciones.
Puedes ampliar la información sobre epoll en el manual de programador Linux mientras que en la página de Apache tienes una documentacion más completa sobre tareas de debugging.

Este artículo ha sido creado por dxr

Proudly powered by WordPress
Theme: Esquire by Matthew Buchanan.