Cache en WordPress usando el Zend Framework

Zend Framework
Desde hace tiempo, este blog está superando los 1000 visitantes diarios y las 2300 páginas vistas. Eso empieza a plantearme algunos problemas, sobre todo teniendo en cuenta la cantidad de recursos que consume el wordpress y que a mí me gusta mucho optimizar el rendimiento del servidor.

Es por eso que he estado buscando alguna forma de añadir cache de páginas al blog. Las opciones que he encontrado han sido:

Pero ninguno de los dos me ha convencido. Lo que yo busco es algo que sea muy eficiente pero a la vez muy simple. Ni siquiera necesito interfaz de administración.

Y es ahí cuando me he dado cuenta de lo evidente… Tanto tiempo usando el Zend Framework y su cache de páginas y no se me había ocurrido aplicarlo al wordpress :P

La instalación es muy sencilla, simplemente he bajado el Zend Framework y he copiado la carpeta «library» a mi directorio raíz de wordpress. Después he creado una carpeta donde irán las páginas cacheadas (en mi caso ha sido: wp-content/cache) que debe tener permiso de escritura (0777).

Y ahora viene lo importante. Hemos de modificar el index.php de wordpress para añadir el código que nos permite usar la cache. Este es ahora mi index.php:


<?php
set_include_path ('library' . PATH_SEPARATOR . get_include_path ());

require_once ‘Zend/Cache.php’;

$frontendOptions = array(
‘lifetime’ => 3600*6,
‘debug_header’ => false, // for debugging
‘default_options’ => array(
‘cache_with_session_variables’ => true,
‘cache_with_cookie_variables’ => true
),
‘regexps’ => array(
‘^/$’ => array(‘cache’ => false),
‘^/2007/’ => array(‘cache’ => true),
‘^/category/’ => array(‘cache’ => true),
‘^/2008/’ => array(‘cache’ => true)
)
);
$backendOptions = array(
/* cache_dir debe ser una ruta absoluta por temas del ob_start */
‘cache_dir’ => dirname($_SERVER[‘SCRIPT_FILENAME’]) . ‘/wp-content/cache/’
);

// getting a Zend_Cache_Frontend_Page object
$cache = Zend_Cache::factory(‘Page’, ‘File’, $frontendOptions, $backendOptions);
$cache->start();

/* Short and sweet */
define(‘WP_USE_THEMES’, true);
require(‘./wp-blog-header.php’);
?>

Podeis encontrar documentación sobre el sistema de cache del Zend Framework aquí. Pero básicamente lo que hago es cachear todos los posts y los listados de las categorías durante 6 horas (3600 segundos * 6). De esta forma, durante esas 6 horas, si se accede a alguno de los posts del blog o a alguna categoría, se tomará la copia de cache y se evitará el pasar por todo el codigo de wordpress, incluida la conexión a la base de datos.

Lo malo de esta solución es que cuando vuelva a actualizar wordpress, tendré que acordarme de no pisar el index.php.

Publicado por

manuel

Me dedico al desarrollo de aplicaciones. Principalmente trabajo con XHTML, CSS, Javascript, XML, JSON, PHP, MySQL, Linux/MacOS X y Flash actionscript. Intento siempre trabajar con estándares y simplificar el desarrollo y las aplicaciones finales con el objetivo de orientarlas al usuario (que sean útiles y faciliten el trabajo).

6 comentarios en «Cache en WordPress usando el Zend Framework»

  1. Muy interesante Manuel, ahora la pregunta es ¿qué diferencia de consumo real hay frente a WP-Cache? Por ejemplo el número de peticiones que puedes realizar por segundo compárandolo con WP-Cache.

    Una forma simple de verlo es con Apache Benchmark:

    /usr/sbin/ab -t 10 -c 10 url

    Si pudieras comparar dos escenarios (uno sin el Zend pero con WP-Cache y otro con el Zend y sin WP-Cache) a ver qué tal…

    PD: quizá te interese probar APC/eAccelerator para rematar la faena.

  2. con Zend Framework
    ———————————————————–
    Benchmarking http://www.ingeniuz.com (be patient)
    Finished 72 requests

    Server Software: Apache/1.3.37
    Server Hostname: http://www.ingeniuz.com
    Server Port: 80

    Document Path: /
    Document Length: 36747 bytes

    Concurrency Level: 10
    Time taken for tests: 10.1976 seconds
    Complete requests: 72
    Failed requests: 0
    Write errors: 0
    Total transferred: 2782554 bytes
    HTML transferred: 2760726 bytes
    Requests per second: 7.20 [#/sec] (mean)
    Time per request: 1389.163 [ms] (mean)
    Time per request: 138.916 [ms] (mean, across all concurrent requests)
    Transfer rate: 271.65 [Kbytes/sec] received

    Connection Times (ms)
    min mean[+/-sd] median max
    Connect: 59 192 70.9 223 277
    Processing: 820 1100 361.5 945 2304
    Waiting: 186 456 418.3 267 1768
    Total: 897 1292 312.2 1181 2363

    Percentage of the requests served within a certain time (ms)
    50% 1181
    66% 1183
    75% 1238
    80% 1310
    90% 1740
    95% 2252
    98% 2320
    99% 2363
    100% 2363 (longest request)

    Con Wp-Cache
    ———————————————
    Benchmarking http://www.ingeniuz.com (be patient)
    Finished 70 requests

    Server Software: Apache/1.3.37
    Server Hostname: http://www.ingeniuz.com
    Server Port: 80

    Document Path: /
    Document Length: 36801 bytes

    Concurrency Level: 10
    Time taken for tests: 10.1993 seconds
    Complete requests: 70
    Failed requests: 60
    (Connect: 0, Length: 60, Exceptions: 0)
    Write errors: 0
    Total transferred: 2673042 bytes
    HTML transferred: 2644166 bytes
    Requests per second: 7.00 [#/sec] (mean)
    Time per request: 1428.856 [ms] (mean)
    Time per request: 142.886 [ms] (mean, across all concurrent requests)
    Transfer rate: 260.95 [Kbytes/sec] received

    Connection Times (ms)
    min mean[+/-sd] median max
    Connect: 57 194 67.9 213 304
    Processing: 276 1160 671.2 973 3456
    Waiting: 71 499 680.8 252 2706
    Total: 339 1354 637.6 1187 3546

    Percentage of the requests served within a certain time (ms)
    50% 1187
    66% 1187
    75% 1187
    80% 1187
    90% 2521
    95% 2901
    98% 3495
    99% 3546
    100% 3546 (longest request)

    La verdad es que es la primera vez que uso Apache Benchmark y no sé interpretar del todo bien los resultados, pero a mí me parece que el Zend Framework sale ganando. Cosa que me parece lógica, ya que no llega a entrar en el codigo de WordPress, evitando así cientos de includes y otros cálculos.

  3. Hola de nuevo, efectivamente el Zend sale ganando aunque por muy poco (7.2 peticiones/seg frente a 7.0 peticiones/seg). Ahora que me fijo le veo tres problemas ahí que deberías tener en cuenta:

    * La lista de ficheros a cachear hay que ir actualizándola (por ejemplo habrá que añadir 2008 cuando llegue el año).
    * La cache no se refresca con los nuevos comentarios hasta pasadas las 6 horas.
    * No has incluido los feeds (muy importante)

    Nota: si la página está cacheada con WP-Cache, tampoco se llega a entrar en el código de WordPress (el WP-Cache lo intercepta antes de que se haga todo lo que dices). Dos pruebas de ello son:

    * Una página puede llegar a gastar 6MB de RAM desde que se carga el script hasta que la página es generada y enviada. Con WP-Cache eso baja a 150KB…
    * Cualquier función de WP no puede ser usada de forma dinámica en la página cacheada (ya que al no cargarse el WP tampoco se cargan esas funciones).

    En cualquier caso, la idea es lo suficiente genérica como para poder ponerla en práctica en otros sitios que no tienen un sistema de cache propio.

  4. En cochez.es estuvimos probando el wp-cache y no nos convenció, ya que a pesar de ganar rendimiento, si un usuario añade un anuncio de coche no sería muy útil que se viera 6 horas después. Por eso probamos con el mod_deflate y el rendimiento mejoró incluso más que con el wp-cache.

    Es decir, simplemente añadimos en el .htaccess la siguientes lineas:
    AddOutputFilterByType DEFLATE text/html text/plain text/xml text/javascript text/css
    BrowserMatch ^Mozilla/4 gzip-only-text/html
    BrowserMatch ^Mozilla/4\.0[678] no-gzip
    BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

    Y así no tocamos nada más.

  5. Respecto lo que comenta Manuel:
    Ummm… la verdad que el benchmarking de Apache (ab) me suscita bastantes dudas:

    A saber, me ha dado resultados totalmente al contrario de los benchmarks ya clásicos sobre php, sobre todo en las funciones sobre arrays y bucles, y lo cierto por otra parte, es que realmente son más rápidos.

    Por ejemplo, los clásicos:
    Un array_push o un array_unique según ab son más rápidos y de hecho, como digo, la carga de la página parece ser más rápida… aún así, todas las pruebas habidas y por haber que he encontrado dicen que:
    $array[] y array_flip recursivo son menos costosos… oO?

    Unas pruebas con una concurrencia de 5 sobre 30 segundos por petición. Mismas respuestas procesadas, etc… Probado en local como online, así que lo dicho, imagino que se tratará del servidor local.


    Pero mi comentario vienen de haber comprobado que alguien usa el excelente framework de Zend sobre Worpdress con buenos resultados.
    En mi opinión… WordPress necesitaría ya, dado su volumen y perspectivas actuales, un framework porque me da la impresión que se les está atragantando y no creo que WP se pueda considerar como tal si no una colección de librerías.

    En cualquier caso llevo mucho tiempo desarrollando un Theme que implemente un CMS para la administración local y estaba harto de lidiar con el Codex o de currarte funcionalidades propias. Esto me anima a usar el framework de Zend ^^!

    Un saludo.

  6. Respecto al caché… yo actualmente sólo genero un caché estático y de servidor para webservices y xml externos con cron, aunque la web no es ni muy dinámica ni muy estática, tampoco me hace demasiada gracia un sistema de caché completo, pero aún así uso los expires ya que el usuario sigue teniendo el control sobre la caché aunque sea menos eficiente.
    Eso, como dice Gorka, junto a salidas comprimidas con php o apache, mejora bastante la cosa obteniendo una buena puntuación con yslow.

    El problema es que uso un cutre-sistema propio de caché para esos datos de webservices, no he usado nunca Zend y llevo tiempo queriéndo hacerlo así o con Pear.
    Lo cierto es que ahora mismo no sé por dónde cogerlo para simplemente cachear archivos, es decir, no páginas completas y sin saluda alguna al navegador :S

    Un saludo, muy interesante toda la entrada y comentarios.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *