Archive for July, 2010

30 de Julio día del SysAdmin

July 30th, 2010

Felicidades a todos los administradores de sistemas, incluyendo a los BOFH :D

http://www.sysadminday.com/

[php] Depurando / Profiling en php ( II )

July 28th, 2010

En este caso analizamos un hecho real, una web que tarda en cargar aleatoriamente entre 10 y 12 segundos. El problema es que al medir los tiempos en otro servidor no llega a 2 segundos. Después de revisar conectividad, carga de sistema, carga de apache … y demás parámetros habituales; todo estaba perfecto. Así que decidimos relizar el profiling de la web para localizar el cuello de botella dentro de los scripts php.

En el artículo anterior [php] Depurando / Profiling en php ( I ) dejamos instalado el módulo APD para capturar la información necesaria y luego procesarla. Recordamos que hay que usar la función apd_set_pprof_trace(); para que se generen los datos. En nuestro caso hemos seleccionado la ruta /tmp en donde se almacenarán estos ficheros.

Ejecutamos unos cuantas veces el script php que nos interesa. Generamos una captura de una ejecución en 1-2 segundos (/tmp/pprof.32231.1) y seguimos ejecutando hasta que conseguimos una captura de datos de una ejecución que tardó unos 10-11 segundos (/tmp/pprof.01666.0)

Vamos a comparar la captura de los datos :

La ejecución buena :

# pprofp -R /tmp/pprof.32231.1

Trace for /var/www/vhosts/hostingaldescubierto.com/httpdocs/index.php
Total Elapsed Time = 0.36
Total System Time  = 0.03
Total User Time    = 0.07

Real         User        System             secs/    cumm
%Time (excl/cumm)  (excl/cumm)  (excl/cumm) Calls    call    s/call  Memory Usage Name
--------------------------------------------------------------------------------------
100.0 0.00 0.36  0.00 0.07  0.00 0.03     1  0.0000   0.3589            0 main
96.1 0.00 0.34  0.00 0.08  0.00 0.03     5  0.0000   0.0690            0 require_once
59.1 0.00 0.21  0.00 0.01  0.00 0.00     8  0.0000   0.0265            0 include
58.9 0.00 0.21  0.00 0.01  0.00 0.00     1  0.0000   0.2113            0 call_user_func_array
58.9 0.00 0.21  0.00 0.01  0.00 0.00     1  0.0000   0.2113            0 Pages->index
58.9 0.00 0.21  0.00 0.01  0.00 0.00     1  0.0000   0.2112            0 Pages->show
58.9 0.00 0.21  0.00 0.01  0.00 0.00     1  0.0000   0.2112            0 Template->build
58.8 0.00 0.21  0.00 0.01  0.00 0.00     2  0.0000   0.1054            0 MY_Loader->view
58.6 0.00 0.21  0.00 0.01  0.00 0.00     2  0.0000   0.1052            0 MY_Loader->_ci_load
56.8 0.00 0.20  0.00 0.00  0.00 0.00     1  0.0000   0.2038            0 weather_google_api
56.8 0.20 0.20  0.00 0.00  0.00 0.00     1  0.2037   0.2037            0 simplexml_load_file
29.4 0.00 0.11  0.00 0.05  0.00 0.02     1  0.0000   0.1054            0 Pages->Pages
29.2 0.00 0.10  0.00 0.05  0.00 0.02     1  0.0000   0.1048            0 Pages->Public_Controller
13.9 0.00 0.05  0.00 0.03  0.00 0.02     1  0.0000   0.0497            0 Pages->MY_Controller
13.4 0.00 0.05  0.00 0.02  0.00 0.03     2  0.0000   0.0241            0 MY_Loader->_ci_autoloader
12.2 0.00 0.04  0.00 0.01  0.00 0.00     3  0.0000   0.0146            0 Banners_model->get_by_section
11.7 0.00 0.04  0.00 0.00  0.00 0.00    25  0.0000   0.0017            0 CI_DB_mysql_driver->query
11.5 0.00 0.04  0.00 0.01  0.00 0.00     6  0.0000   0.0069            0 Banners_model->add_hit
11.4 0.04 0.04  0.03 0.03  0.01 0.01    65  0.0006   0.0006            0 defined
10.9 0.00 0.04  0.00 0.00  0.00 0.00    25  0.0000   0.0016            0 CI_DB_mysql_driver->simple_query

El fichero de 10-12 segundos :

# pprofp -R /tmp/pprof.01666.0

Trace for /var/www/vhosts/hostingaldescubierto.com/httpdocs/index.php
Total Elapsed Time = 10.34
Total System Time  = 0.02
Total User Time    = 0.08

Real         User        System             secs/    cumm
%Time (excl/cumm)  (excl/cumm)  (excl/cumm) Calls    call    s/call  Memory Usage Name
--------------------------------------------------------------------------------------
100.1 0.00 10.35  0.00 0.09  0.00 0.02     5  0.0000   2.0692            0 require_once
100.0 0.00 10.34  0.00 0.08  0.00 0.02     1  0.0000   10.3394            0 main
99.1 0.00 10.24  0.00 0.01  0.00 0.00     8  0.0000   1.2802            0 include
99.0 0.00 10.24  0.00 0.01  0.00 0.00     1  0.0000   10.2409            0 call_user_func_array
99.0 0.00 10.24  0.00 0.01  0.00 0.00     1  0.0000   10.2409            0 Pages->index
99.0 0.00 10.24  0.00 0.01  0.00 0.00     1  0.0000   10.2409            0 Pages->show
99.0 0.00 10.24  0.00 0.01  0.00 0.00     1  0.0000   10.2409            0 Template->build
99.0 0.00 10.24  0.00 0.01  0.00 0.00     2  0.0000   5.1202            0 MY_Loader->view
99.0 0.00 10.24  0.00 0.01  0.00 0.00     2  0.0000   5.1200            0 MY_Loader->_ci_load
99.0 0.00 10.23  0.00 0.00  0.00 0.00     1  0.0000   10.2335            0 weather_google_api
99.0 10.23 10.23  0.00 0.00  0.00 0.00     1  10.2333   10.2333            0 simplexml_load_file
0.7 0.00 0.08  0.00 0.06  0.00 0.01     1  0.0000   0.0766            0 Pages->Pages
0.7 0.00 0.08  0.00 0.05  0.00 0.01     1  0.0000   0.0761            0 Pages->Public_Controller
0.5 0.00 0.05  0.00 0.04  0.00 0.01     2  0.0000   0.0266            0 MY_Loader->_ci_autoloader
0.5 0.00 0.05  0.00 0.04  0.00 0.01     1  0.0000   0.0524            0 Pages->MY_Controller
0.4 0.04 0.04  0.04 0.04  0.01 0.01    65  0.0006   0.0006            0 defined
0.4 0.00 0.04  0.00 0.02  0.00 0.01    38  0.0000   0.0010            0 MY_Loader->helper
0.3 0.00 0.04  0.00 0.03  0.00 0.00    10  0.0000   0.0036            0 MY_Loader->model
0.3 0.00 0.03  0.00 0.02  0.00 0.01     1  0.0000   0.0312            0 Pages->Controller
0.3 0.00 0.03  0.00 0.02  0.00 0.01     1  0.0000   0.0311            0 Pages->_ci_initialize

Vemos claramente esta linea que es la que penaliza el tiempo de ejecución del script:

99.0 10.23 10.23  0.00 0.00  0.00 0.00     1  10.2333   10.2333            0 simplexml_load_file

Perfecto, ya sabemos lo que tenemos que buscar el uso de la función simplexml_load_file. Buscamos los ficheros que usan esta funcion, por ejemplo así :

find -name "*php" -exec grep -l simplexml_load_file {} \;

Entre los resultados encontramos uno, que llama especialmente la atención, en el que solicita un fichero xml de google http://www.google.com/ig/api?weather=madrid&oe=utf-8.
Vamos a medir cuanto tiempo tarda en descargarlo :

# time wget 'http://www.google.com/ig/api?weather=madrid&oe=utf-8'
--2010-07-26 18:27:47--  http://www.google.com/ig/api?weather=madrid&oe=utf-8
Resolving www.google.com... 66.249.92.104
Connecting to www.google.com|66.249.92.104|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/xml]
Saving to: `api?weather=madrid&oe=utf-8.1'

[ <=>                                                                                                                                      ] 1,291       --.-K/s   in 0s

2010-07-26 18:27:57 (12.0 MB/s) - `api?weather=madrid&oe=utf-8.1' saved [1291]

real    0m10.157s
user    0m0.002s
sys    0m0.001s

Parece bastante claro que la ejecución se ralentiza por la petición a google… una caché que se actualice cada día, hora o cada minuto solucionaría este problema.

[xinetd] FAIL: smtp per_source_limit from

July 27th, 2010

Otro caso común es que los clientes que usan IMAP padecen errores de desconexión al chequear la cuenta. En Outlook por ejemplo aparece este error:

(0x8004DF0B): ‘ Outlook no puede descargar la carpeta (null) del servidor de correo electrónico IMAP para la cuenta hostingaldescubierto. Error : la conexión con el servidor no está disponible. Outlook debe estar en linea o conectado para completar esta acción. Si sigue recibiendo ste mensaje, póngase ne contacto con el adminsistrador del servidor o con el proveedor de servicios de Internete (ISP).’

El servicio imap limita el número de conexiones concurrentes desde una misma ip y en aplicaciones como thunderbird que abre varios threads o en oficinas con varios puestos de trabajo podemos llegar a usar el máximo de conexiones permitidas. Para verificarlo, podemos buscar en el fichero messages ( ejemplo de una instalación con CentOS ) :

grep xinet messages | egrep -v "(START|EXIT)"

Jul 25 08:03:09 host05 xinetd[14777]: warning: can't get client address: Connection reset by peer
Jul 25 09:59:07 host05 xinetd[9558]: warning: can't get client address: Connection reset by peer
Jul 25 11:21:46 host05 xinetd[30946]: FAIL: smtp per_source_limit from=69.63.178.184
Jul 25 11:21:52 host05 xinetd[30946]: FAIL: smtp per_source_limit from=69.63.178.184
Jul 25 11:21:53 host05 xinetd[30946]: FAIL: smtp per_source_limit from=69.63.178.184
Jul 25 15:16:25 host05 xinetd[27990]: warning: can't get client address: Connection reset by peer
Jul 25 15:16:25 host05 xinetd[27991]: warning: can't get client address: Connection reset by peer
Jul 25 16:37:20 host05 xinetd[32733]: warning: can't get client address: Connection reset by peer

y buscamos el número de conexiones posibles:

grep MAXPERIP /etc/courier-imap/imapd
MAXPERIP=4

Con lo que vemos que el máximo de conexiones son 4 por IP, lo ampliamos manualmente como más nos guste y reiniciamos el servicio.

/etc/init.d/courier-imap restart
 Stopping Courier-IMAP server:
 Stopping imap                                           [  OK  ]
 Stopping imap-ssl                                       [  OK  ]
 Stopping pop3                                           [  OK  ]
 Stopping pop3-ssl                                       [  OK  ]

Starting Courier-IMAP server:
 Starting imapd                                          [  OK  ]
 Starting imap-ssl                                       [  OK  ]
 Starting pop3                                           [  OK  ]
 Starting pop3-ssl                                       [  OK  ]

Este caso suele ser muy típico en instalaciones con Plesk.

[php] Depurando / Profiling en php ( I )

July 23rd, 2010

Para poder diagnosticar qué sucede en la máquina cuando se ejecuta un script en php es necesario instalar un depurador o profiler. En este caso instalamos Advanced Php Debugger.

En máquinas Centos, como es usual no lo tenemos en el repositorio así lo instalaremos manualmente usando ‘pecl‘ que lo provee el paquete de php-pear .

pecl install apd

Será necesario tener instalado make, gcc  y autconf

Nos podemos encontrar con este error :

# pecl install apd
WARNING: channel "pear.php.net" has updated its protocols, use "channel-update pear.php.net" to update
downloading apd-1.0.1.tgz ...
Starting to download apd-1.0.1.tgz (36,643 bytes)
..........done: 36,643 bytes
15 source files, building
running: phpize
Configuring for:
PHP Api Version:         20041225
Zend Module Api No:      20060613
Zend Extension Api No:   220060519
building in /var/tmp/pear-build-root/apd-1.0.1
running: /tmp/pear/download/apd-1.0.1/configure
checking for egrep... grep -E
checking for a sed that does not truncate output... //bin/sed
checking for cc... cc
checking for C compiler default output file name... a.out
checking whether the C compiler works... configure: error: cannot run C compiled programs.
If you meant to cross compile, use `--host'.
See `config.log' for more details.
ERROR: `/tmp/pear/download/apd-1.0.1/configure' failed

Normalmente es debido a que tenemos /var y /var/tmp con la opcion de noexec. Para poder ejecutarlo correctamente pondremos temporalmente estos puntos de montaje con permisos de ejecución y luego lo restauramos:

mount -o,remount,rw,exec /var/tmp
mount -o,remount,rw,exec /tmp
pecl install apd
mount -o,remount,rw,noexec /var/tmp
mount -o,remount,rw,noexec /tmp

Nos insteresa quedarnos con este contenido para configurar el fichero .ini :

running: make INSTALL_ROOT="/var/tmp/pear-build-root/install-apd-1.0.1" install
Installing shared extensions:     /var/tmp/pear-build-root/install-apd-1.0.1/usr/lib64/php/modules/
running: find "/var/tmp/pear-build-root/install-apd-1.0.1" | xargs ls -dils
  12   1 drwxr-xr-x 3 root root   1024 Jul 23 18:33 /var/tmp/pear-build-root/install-apd-1.0.1
2057   1 drwxr-xr-x 3 root root   1024 Jul 23 18:33 /var/tmp/pear-build-root/install-apd-1.0.1/usr
4113   1 drwxr-xr-x 3 root root   1024 Jul 23 18:33 /var/tmp/pear-build-root/install-apd-1.0.1/usr/lib64
6169   1 drwxr-xr-x 3 root root   1024 Jul 23 18:33 /var/tmp/pear-build-root/install-apd-1.0.1/usr/lib64/php
8225   1 drwxr-xr-x 2 root root   1024 Jul 23 18:33 /var/tmp/pear-build-root/install-apd-1.0.1/usr/lib64/php/modules
8226 129 -rwxr-xr-x 1 root root 130196 Jul 23 18:33 /var/tmp/pear-build-root/install-apd-1.0.1/usr/lib64/php/modules/apd.so

Build process completed successfully
Installing '/usr/lib64/php/modules/apd.so'
install ok: channel://pear.php.net/apd-1.0.1

Tendremos que crear un fichero en /etc/php.d/apd.ini con este contenido

zend_extension = /usr/lib64/php/modules/apd.so
apd.dumpdir = /tmp
apd.statement_tracing = 0

y comprobamos que el modulo carga con php -m

#php -m

....

[Zend Modules]
Advanced PHP Debugger (APD)
Zend Optimizer

Ahora ya podemos lanzar el profiling en nuestras páginas, para ello podemos incrustar este fragmento de código y activarlo sólamente cuando accedamos nosotros y no los clientes:

 <?php
 $DEBUGIPS = array('93.174.6.8','192.168.1.1');
 if(array_search($_SERVER[REMOTE_IP], $DEBUGIPS)) {
   apd_set_pprof_trace();
 }
?>

Y con esto acabamos la primera parte, atentos a la segunda :D

[wordpress] Fatal error: Call to undefined function wp() in /var/www/vhosts/dominio.tld/httpdocs/wordpress/wp-blog-header.php on line 14

July 16th, 2010

Al hacer una instalación nueva de wordpress, puedes contrarte con este error :

Fatal error: Call to undefined function wp() in /var/www/vhosts/dominio.tld/httpdocs/wordpress/wp-blog-header.php on line 14

Es debido a que el fichero wp-config.php esté vacio o mal configurado. La mejor opción es coger el fichero wp-config-sample.php y rellenarlo a mano. Sólo hay que especificar base de datos, usuariom, password y host.

Puedes usar esta plantilla para wordpress 3.0 si no tienes nada a mano

<?php

define('DB_NAME', 'nombre_base_datos');

/** MySQL database username */
define('DB_USER', 'usuario');

/** MySQL database password */
define('DB_PASSWORD', 'password');

/** MySQL hostname */
define('DB_HOST', 'localhost');

/** Database Charset to use in creating database tables. */
define('DB_CHARSET', 'utf8');

/** The Database Collate type. Don't change this if in doubt. */
define('DB_COLLATE', '');

#
# generado automaticametne desde:
# https://api.wordpress.org/secret-key/1.1/salt/
#

define('AUTH_KEY',         'pQ<@NK%: 42QBJ&$bhPZZzqs!vGZ}8Ph$R>j~x8}Z+V+[%]10Z~oy!N#^#/pT&}l');
define('SECURE_AUTH_KEY',  ';CT`bP|YA>[+|i(Kza+*K4x<[8ce(cfEzJefBUnlm$kGo=|+#MDuc+3Eka3oEcUp');
define('LOGGED_IN_KEY',    'Ym_wh[WKu;q_}@N$Y<A?u{{W5hg3&^K5`l~RTIdiO;=|TiG/BD~FMWF b^qz7L_4');
define('NONCE_KEY',        'qDwCcdk?T8-PHo pFNOu(yCUsi0^<$lP05A/A=D2PZ+5|xZ<-z:Z&=p?7$JK:hUT');
define('AUTH_SALT',        'YTJ1VYm1m[-9),*uxvB#c@MgFBAVpf6m~8Eg._uZ(|$c-%nsM}_#3&48=H_E2PY<');
define('SECURE_AUTH_SALT', '{RNOa149Lnw6jyQDMJ9L%KUTXoir.R$NLO.BHO=,A]#G;=C$ OS_>4ed+l}ZUpF}');
define('LOGGED_IN_SALT',   '<fu@&qA2j&NK]1RLOI 0QtH/NY%.8ufHJrwum kc9>Cmv!h}pkYHU.<y~1%#y09o');
define('NONCE_SALT',       'G1NkJF3E3xI_KFu|[oLk??o6GagegY(6*=Gkk!adIv%bUNnU #@7R&ZI85;~R$ki');

$table_prefix  = 'wp_';

define ('WPLANG', '');

define('WP_DEBUG', false);

if ( !defined('ABSPATH') )
        define('ABSPATH', dirname(__FILE__) . '/');

require_once(ABSPATH . 'wp-settings.php');

Nota: el fichero acaba sin cerrar el script php , SIN ?>

Debian Etch 4.0 : descatalogada y obsoleta

July 8th, 2010

Desde esta semana Debian Etch es historia y queda en archives.debian.org para la posteridad. Aunque el soporte acababa en Febrero de 2010 se anunció la novena actualización el 22 de Mayo de 2010.

Se recomienda pasar a ‘stable’ aunque siempre es posible modificar las fuentes apt indicando en el repositorio :


deb http://archive.debian.org/debian etch main contrib non-free
deb http://archive.debian.org/debian-security etch/updates main contrib non-free

[magento] PHP Fatal error: Exception thrown without a stack frame in Unknown on line 0

July 8th, 2010

Estos últimas días hemos tenido que optimizar la carga de servidores con Magento. Una de las tareas es usar un sistema de caché que acelere los scripts php. Usamos apc por compatibilidad con Magento y por que ya viene paquetizado en los repositorios de Debian.

El problema, aparece en el pié de página: “PHP Fatal error:  Exception thrown without a stack frame in Unknown on line 0″.
Este error aparece cuando se ha lanzado una excepcion en un lugar donde se no se puede lanzar una excepción por no tener ‘stack frame‘.

Los manejadores de excepciones ‘ exception handlers‘ y los destructores no tienen ‘stack frame‘.
Por lo que combinar por ejemplo un ‘execption handler‘ con un ‘error preporting‘  o lanzar un execption en un destructor puede provocar que aparezcan. Os podeis documentar más en este interesante enlace Solving “Fatal error: Exception thrown without a stack frame in Unknown on line 0″

En nuestro caso, tan solo hizo falta acutalizar la version del apc con un simple apt


apt-get install php-apc

En la máquina estaba previamente instalado el apc vía pecl