Apr 26

Como prometía en el post dedicado a la optimización de ADOdb voy a explicar como instalar el sistema de cache APC sobre un servidor FreeBSD 6.x. El APC (Alternative PHP Cache) es un sistema de cache de opcode para PHP, sirve para cachear el código intermedio del PHP y así no tener que interpretar todos los scripts en cada ejecución. Para almacenar este código “compilado” se usa la memoria compartida del sistema. A parte el APC nos ofrece funciones para poder almacenar y recuperar datos de cache.

El APC es una extensión PECL que no viene incluida por defecto con el PHP (esto cambiará con la futura versión 6). A continuación describo como instalar y configurar el APC sobre FreeBSD.

[1] Instalar el port

Suponiendo que tenemos instalado y funcionando un servidor web (Apache+PHP) sólo nos falta añadirle la extensión PECL con:

# portinstall pecl-APC

Si no trabajas con portupgrade:

# cd /usr/ports/www/pecl-APC/
# make install clean

Con esto compilamos e instalamos el APC. Si todo va bien acabará el proceso y podremos ver esta nueva linea en el archivo /usr/local/etc/php/extensions.ini:

extension=apc.so

Cuando lo compilas se dan a escoger tres opciones: MMAP, SEMAPHORES y PHP4_OPT. Es aconsejable seleccionar sólo MMAP y si trabajas con PHP4 la última también. La opción de SEMAPHORES dependiendo de tu sistema puede provocar cierta inestabilidad y no ofrece muchas mejoras en rendimiento.

La última versión del APC (pecl-APC-3.0.14) se compila siempre con soporte mmap aunque desactives la opción (o esto es lo que me pasa a mi en los servidores bajo FreeBSD).

Ahora sólo falta configurar correctamente las directivas apropiadas en el php.ini y un restart (o reload) del Apache.

[2] Configurando el APC

La configuración por defecto del APC es apropiada en muchas situaciones aunque bajo FreeBSD deberíamos configurar correctamente el tamaño de memoria compartida. Esto se consigue con las siguientes directivas:

apc.shm_segments=1
apc.shm_size=32

En FreeBSD el tamaño de memoria compartida por defecto es de 32MB. Puedes optar por aumentarlo o por dejarlo igual y usar varios segmentos configurando la directiva apc.shm_segments. Para aumentar el tamaño de la memoria compartida a 128MB en FreeBSD:

# sysctl kern.ipc.shmmax=134217728
# sysctl kern.ipc.shmall=32768

Si quieres conservar estos valores después de reiniciar el sistema debes añadirlos en /etc/sysctl.conf.

Se debe fijar SHMALL (kern.ipc.shmall) a SHMMAX/PAGE_SIZE. Este valor en el ejemplo descrito de 128MB de memoria compartida nos queda como: 134217728/4096 = 32768. Puedes ejecutar el comando pagesize para conocer el tamaño de una página de memoria (PAGE_SIZE) en tu sistema y ipcs -M para verificar la configuración de la memoria compartida.

También hacer notar en este punto que con la última versión del APC bajo FreeBSD no permite usar varios segmentos de memoria compartida y estás obligado a sólo usar un segmento, si necesitas más memoria debes aumentar el tamaño de memoria compartida del sistema.

El resto de directivas de configuración dependen mucho del tipo de aplicación PHP. Dependiendo del número de visitas, cantidad de archivos a cachear, frecuencia de cambio de los archivos, etc. Una configuración de ejemplo con pequeñas notas acerca del significado de las directivas usadas (en el archivo /usr/local/share/doc/APC/INSTALL tienes todas las directivas disponibles detalladas):

; Activa el APC
apc.enabled=1
; Número de segmentos de memoria compartida
apc.shm_segments=1
; Tamaño de la memoria compartida
apc.shm_size=128
; Un número aproximado de archivos fuente a cachear
apc.num_files_hint=6000
; Un número aproximado de variables a cachear
apc.user_entries_hint=100
; Segundos que dejamos en cache una entrada que ya no se usa
apc.ttl=600
; Idem al anterior pero para las variables de usuario
apc.user_ttl=600
; Segundos que dejamos una entrada cacheada en el recolector de basura
apc.gc_ttl=0
; Indica si se cachea por defecto.
apc.cache_by_default=On
; Expresiones regulares para saber que archivos cacheamos
; Resulta útil si se usa en combinación con la directiva anterior
apc.filters=""
; Indica si se activa el APC para el modo CLI del PHP
apc.enable_cli=0
; Indica el tamaño máximo de archivos a cachear
apc.max_file_size=1M
; Indica si el APC ha de verificar si los archivos han sido modificados
; para actualizar la cache
apc.stat=1

De todos los cacheadores de código que he usado APC es con diferencia el más estable aunque no es perfecto. En situaciones de mucho tráfico y si constantemente estás cambiando los archivos al final consigues un fantástico segfault del Apache. Una gran opción si dispones de una aplicación que no está en constante desarrollo es usar la directiva apc.stat a 0, con este parámetro consigues mucha más estabilidad.

Es un gran invento y es muy recomendable su uso, puedes llegar a ver loads de CPU reducidos al 50% y ganar un 20% de memoria. Pero como todo tiene bugs y al menos yo en el escenario donde lo uso (decenas de millones de páginas vistas por mes + clúster de decenas de servidores BSD) es un tanto inestable en ciertas situaciones… pero mucho más estable que algo como EAccelerator el cual en el anterior escenario no aguanta ni 5 minutos.

Si usas APC sobre FreeBSD en webs con mucho tráfico y no tienes ni un segfault nunca… no te cortes y comenta que directivas/opciones estás usando.

En un siguiente post explicaré como usar las funciones que proporciona el APC para almacenar datos de aplicación en cache.

Tagged with:
Apr 25

Una de las técnicas más habituales en el desarrollo de aplicaciones PHP orientadas a objetos es crear un archivo fuente para cada definición de clase. Con esta técnica es necesario hacer require de muchos archivos en el código para cada ejecución. Nuestro fantástico PHP5 nos ofrece la posibilidad de cargar automáticamente las clases que necesita bajo demanda definiendo la función __autoload().

Otra gran ventaja de usar autoload es que nos aseguramos de que sólo incluimos las definiciones de las clases que realmente usamos. Es frecuente en la vida de una aplicación que debido a actualizaciones se nos queden requires de clases que ya no usamos o que por ejemplo tengamos la costumbre de hacer todos los requires que va a usar una clase en la cabecera, entonces para ejecutar un sólo método que quizás sólo usa un par de clases estamos cargando clases innecesarias.

A pesar de que normalmente el uso de autoload provoca una mejora importante en el rendimiento ya que sólo se cargan las clases que usamos se ha de tener en cuenta que el código que tengamos en la función __autoload() debe ser lo más ligero posible ya que dependiendo del tamaño de la aplicación se va a ejecutar muchísimas veces.

Una función __autoload() de ejemplo podría ser algo como:

[php] function __autoload($class_name) {
$file = ‘/classes/’.$class_name.’.php’;
if (file_exists($file)) require_once $file;
} [/php]

Si tiras de file_exists() y constantemente estás añadiendo y quitando clases quizás te resulta interesante usar clearstatcache() antes para limpiar la cache de estados de archivo.

Como es necesario definir el autoload al principio de cada script resulta útil usar la directiva auto_prepend_file, si no tienes acceso a tu PHP.INI puedes añadir lo siguiente en tu .htaccess:

php_value auto_prepend_file "funcion_autoload.php"

Una última consideración es que en teoría no se pueden lanzar exceptions desde dentro de la función __autoload(), aunque usando eval() para cargar la definición de la clase exception deseada lo puedes conseguir (en las notas del manual tienes varios ejemplos).

Tagged with:
Apr 19

Un tema no relacionado con PHP o BSD pero con mucha relación con este blog… Llevo más de 20 días sin inet en casa… brrr :( Todo “gracias” a Tele2.

Por mi parte Tele2… nunca máis. Esto de trabajar con alguien que no tiene control sobre su infraestructura… nunca máis. Es cierto q llevaba un año sin incidencias, pero cuando tienes una relacionada con la linea de teléfono estás perdido. En estos casos han de intentar “trabajar” conjuntamente Telefónica y Tele2… y pocas veces lo consiguen.

Ale, espero recuperar la situación en breve y q este blog vuelva a tener más actividad :)

Tagged with:
preload preload preload