Symfony 2.0, el libro oficial

14.2. Las cachés de tipo gateway cache

Cuando utilizas la caché de HTTP, el sistema de caché es completamente independiente de tu aplicación y se comporta como una capa entre tu aplicación y el cliente que realiza la petición.

El objetivo de la caché es aceptar las peticiones del cliente y pasarlas a tu aplicación. La caché también recibe las respuestas que genera tu aplicación y las envía al cliente. La caché es el elemento que se encuentra justo en el medio de la comunicación entre los clientes y tu aplicación.

Durante este proceso, la caché almacena todas las respuestas que se consideran cacheables. De esta forma, si se solicita de nuevo la misma página, la caché envía de inmediato al cliente la página que se encuentra en la caché, evitando completamente la ejecución de la aplicación.

Este tipo de caché se denomina gateway cache y en el mercado existen muchas cachés de este tipo, como por ejemplo Varnish, Squid y el proxy inverso de Symfony2.

14.2.1. Tipos de caché

Las gateway caches no son el único tipo de caché que existe. En realidad, las cabeceras HTTP relacionadas con la caché que añade tu aplicación afectan a tres tipos diferentes de caché:

  • Caché del navegador: cada navegador viene con su propia caché local, que es muy útil cuando pulsas "atrás" o para guardar imágenes y otros tipos de archivos. La caché del navegador es una caché privada porque los recursos almacenados no se comparten con nadie más.
  • Proxy cache: los proxy son cachés compartidas porque normalmente detrás de ellas se encuentran muchas personas. Normalmente se instalan en empresas grandes y proveedores de Internet para reducir la latencia y el tráfico de red.
  • Gateway cache: al igual que los proxy cache, también es una caché compartida pero siempre se encuentra en el lado del servidor. Normalmente la instalan los administradores de la red de la empresa que ha desarrollado la aplicación, ya que hace que los sitios web sean más escalables, estables y rápidos.

Truco Las gateway caches a veces también se conocen como proxy caches, surrogate caches o incluso, aceleradores HTTP.

Nota Las diferencias entre una caché privada y otra compartida será más evidentes a medida que hablemos de cómo guardar en la caché las respuestas con contenido que es específico para un solo usuario (por ejemplo, la información de su cuenta).

Cada respuesta de tu aplicación probablemente atraviese uno o los dos primeros tipos de caché. Estas cachés están fuera de tu control, pero siempre cumplen con las instrucciones que estableces a través de las cabeceras HTTP de la caché.

14.2.2. El proxy inverso de Symfony2

Symfony2 incluye su propio proxy inverso o reverse proxy (también conocido como gateway cache) escrito en PHP. Actívalo y las respuestas de la aplicación comenzarán a guardarse en la caché inmediatamente. Su instalación es muy fácil, ya que cada nueva aplicación Symfony2 viene con un kernel especial preconfigurado y preparado para la caché (AppCache) que utiliza internamente el kernel por defecto (AppKernel). Este kernel especial (AppCache) es el proxy inverso de Symfony2.

Para habilitar la caché, modifica el código del controlador frontal para utilizar el kernel especial para la caché:

// web/app.php
require_once __DIR__.'/../app/bootstrap.php.cache';
require_once __DIR__.'/../app/AppKernel.php';
require_once __DIR__.'/../app/AppCache.php';

use Symfony\Component\HttpFoundation\Request;

$kernel = new AppKernel('prod', false);
$kernel->loadClassCache();
// el kernel especial AppCache utiliza el kernel AppKernel
$kernel = new AppCache($kernel);
$kernel->handle(Request::createFromGlobals())->send();

El kernel de la caché actúa de inmediato como un proxy inverso, guardando las respuestas de la aplicación en la caché y devolviéndolas al cliente.

Truco El kernel de la caché tiene un método especial llamado getLog(), que devuelve una cadena de texto con la información sobre lo que ha sucedido en la capa de la caché. Puedes utilizar esta información en el entorno de desarrollo para validar que tu estrategia de caché está funcionando correctamente:

error_log($kernel->getLog());

El objeto AppCache ya está preconfigurado con las opciones más comunes para las aplicaciones web habituales, pero puedes modificar todas ellas con el método getOptions():

// app/AppCache.php
use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache;

class AppCache extends HttpCache
{
    protected function getOptions()
    {
        return array(
            'debug'                  => false,
            'default_ttl'            => 0,
            'private_headers'        => array('Authorization', 'Cookie'),
            'allow_reload'           => false,
            'allow_revalidate'       => false,
            'stale_while_revalidate' => 2,
            'stale_if_error'         => 60,
        );
    }
}

Truco A menos que indiques su valor en el método getOptions(), la opción debug tendrá automáticamente el mismo valor que que el establecido en el kernel por defecto de Symfony2 (AppKernel).

Esta es la lista de las principales opciones de configuración:

  • default_ttl: el número de segundos que una página de la caché se considera válida cuando la respuesta no proporciona ninguna información al respecto. Las cabeceras Cache-Control o Expires pueden sobreescribir este valor (valor por defecto: 0);
  • private_headers: lista de cabeceras cuya presencia hace que la respuesta se convierta automáticamente en privada (a menos que la propia respuesta indique explícitamente si es pública o privada mediante la directiva Cache-Control) (valor por defecto: Authorization y Cookie);
  • allow_reload: especifica si el cliente puede forzar que se recargue la caché incluyendo una directiva Cache-Control con el valor no-cache en la petición. Establece esta opción a true si quieres cumplir con el estándar RFC 2616 (valor por defecto: false);
  • allow_revalidate: especifica si el cliente puede forzar una revalidación de caché incluyendo una directiva Cache-Control max-age = 0 en la petición. Ponla en true para cumplir con la RFC 2616 (por omisión: false);
  • stale_while_revalidate: especifica el número de segundos durante el que la caché puede seguir devolviendo páginas caducadas mientras en segundo plano intenta regenerar esa página (valor por defecto: 2). Esta opción se sobreescribe con la opción stale-while-revalidate de la extensión Cache-Control de HTTP (consulta el estándar RFC 5861).
  • stale_if_error: especifica el número de segundos durante el que la caché puede seguir devolviendo páginas caducadas cuando se detecta un error (valor por defecto: 60). Esta opción se sobreescribe con la opción stale-if-error de la extensión Cache-Control de HTTP (consulta el estándar RFC 5861).

Si la opción debug es true, Symfony2 añade automáticamente la cabecera X-Symfony-Cache a las respuestas. Esta cabecera contiene información útil acerca de si la página se ha obtenido de la caché o ha sido generada para la respuesta.

Nota El rendimiento del proxy inverso de Symfony2 es independiente de lo compleja que sea tu aplicación. El motivo es que el kernel de tu aplicación sólo se ejecuta cuando la petición se debe servir desde la aplicación en vez de desde la caché.