Fuente de datos: Memcache


1Presentación

La caché suele usarse para almacenar información que se consulta con frecuencia en lectura. Por eso es preferible no leerla en la base de datos en cada acceso, sino agregarla y ponerla en caché; las lecturas posteriores serán más rápidas.

Hay que entender que, a diferencia de las sesiones, las variables de caché son comunes a toda la aplicación. Por eso es importante pensar bien en la nomenclatura de las variables, para poder encontrarlas fácilmente.
Otra diferencia es que el propósito de las variables de caché es permanecer temporales. Expiran después de cierto tiempo, que puede definirse de forma global o de manera precisa para cada variable. Por defecto, el tiempo de expiración es de 24 horas.

Si has configurado correctamente los parámetros de conexión al servidor Memcached, Temma crea automáticamente un objeto de tipo \Temma\Datasources\Memcache. Por convención, supondremos que has llamado a esta conexión cache en el archivo etc/temma.php (consulta la documentación de configuración).

En los controladores, la conexión a la caché está entonces disponible escribiendo:

$cache = $this->cache;

En los demás objetos gestionados por el componente de inyección de dependencias, la conexión a la caché puede accederse escribiendo:

$cache = $loader->dataSources->cache;
$cache = $loader->dataSources['cache'];

2Configuración

En el archivo etc/temma.php (consulta la documentación de configuración), declaras el DSN (Data Source Name) usado para conectarte al (o a los) servidor(es) Memcache.

Cuando los datos se distribuyen entre varios servidores Memcache, corresponde a los clientes conocer cuáles son esos servidores, y su lista debe configurarse de forma idéntica en todos los clientes que necesiten conectarse a los servidores.

El DSN para conectarte a un servidor Memcache se escribe así: memcache://SERVIDOR[:PORT]
El número de puerto por defecto es 11211.

Cuando hay varios servidores Memcache, sepáralos con punto y coma.
Ejemplo: memcache://localhost;otherhost:11000;anotherhost

Si el servidor Memcache se ejecuta en la misma máquina, es posible conectarse usando un socket Unix, evitando así las latencias de red. En ese caso, el DSN es: memcache://CAMINO
La ruta debe apuntar al socket Unix (a menudo /var/run/memcache/memcached.sock).
Ejemplo: memcache:///var/run/memcache/memcached.sock

Por defecto, las variables de caché se almacenan en un espacio de nombres propio de cada sitio, según el nombre de dominio completo (www.mysite.com, othersite.org, test.othersite.org, etc.). Si necesitas compartir variables de caché entre varios sitios, puedes especificar el espacio de nombres añadiéndolo al final del DSN después de un símbolo de almohadilla (#).

Ejemplos:
memcache://localhost#globalsite.com
memcache://cache.server:11000#globalsite.com
memcache:///var/run/memcache/memcached.sock#cache_namespace


3Llamadas unificadas

3.1Acceso tipo array

// comprobación de la existencia de un dato
if (isset($cache['key1']))
    doSomething();

// lectura de datos (deserializados)
$data = $cache['key1'];

// escritura de datos (serializados)
$cache['key1'] = $value;

// eliminación de datos
unset($cache['key1']);

// número de elementos
$cnt = count($cache);

3.2Métodos generales

// comprobación de la existencia de un dato
if ($cache->isSet('user:1'))
    doSomething();

// eliminación de un dato
$cache->remove('user:1');

// eliminación de varios datos
$cache->mRemove(['user:1', 'user:2', 'user:3']);

// eliminación de datos a partir de un prefijo
$cache->clear('user:');

// eliminación de todos los datos
$cache->flush();

3.3Gestión de datos serializados complejos

Memcache no soporta el método search().

Por defecto, los datos almacenados en Memcache tienen una vida útil de 24 horas. Es posible especificar el número de segundos de caché, hasta 30 días (ya sea especificando 2592000 segundos, o bien indicando un valor de -1).

// lectura de datos (deserializados)
$user = $cache->get('user:1');
// leer datos con valor por defecto
$color = $cache->get('color', 'blue');
// leer datos con creación de datos si es necesario
$user = $cache->get("user:$userId", function() use ($userId) {
    return $this->dao->get($userId);
});

// leer varios datos (deserializados)
$users = $cache->mGet(['user:1', 'user:2', 'user:3']);

// escritura de datos (serializados)
$cache->set('user:1', $userData);
// escritura (serializada) de datos con una vida útil de una hora
$cache->set('user:1', $userData, 3600);

// escritura de varios datos (serializados)
$cache->mSet([
    'user:1' => $user1data,
    'user:2' => $user2data,
    'user:3' => $user3data,
]);
// escritura de varios datos, con una vida útil de 30 días
$cache->mSet([
    'user:1' => $user1data,
    'user:2' => $user2data,
], -1);

3.4Gestión de datos en bruto

Memcache no soporta el método find().

Por defecto, los datos almacenados en Memcache tienen una vida útil de 24 horas. Es posible especificar el número de segundos de caché, hasta 30 días (ya sea especificando 2592000 segundos, o bien indicando un valor de -1).

// leer datos (en bruto)
$html = $cache->read('page:home');
// leer datos con valor por defecto
$html = $cache->read('page:home',
                           '<html><body><h1>Homepage</h1><body><html>');
// leer datos con creación de datos si es necesario
$html = $cache->read('page:home', function() {
    return file_get_contents('/path/to/homepage.html');
});

// leer varios datos (en bruto)
$pages = $cache->mRead(['page:home', 'page:admin', 'page:products']);

// copiar datos a un archivo local
$cache->copyFrom('page:home', '/path/to/newpage.html');
// copiar datos a un archivo local, con valor por defecto
$cache->copyFrom('page:home', '/path/to/newpage.html', $defaultHtml);
// copiar datos a un archivo local, con creación de datos si es necesario
$cache->copyFrom('page:home', '/path/to/newpage.html', function() {
    return file_get_contents('/path/to/oldpage.html');
});
// copiar datos a un archivo local, con creación de datos si es necesario
// (con una vida útil de una hora)
$cache->copyFrom('page:home', '/path/to/newpage.html', function() {
    return file_get_contents('/path/to/oldpage.html');
}, 3600);

// escritura de datos (en bruto)
$cache->write('color:blue', '#0000ff');
// escritura de datos (en bruto) con una vida útil de una hora
$cache->write('color:blue', '#0000ff', 3600);

// escritura de varios datos (en bruto)
$cache->mWrite([
    'color:blue'  => '#0000ff',
    'color:red'   => '#ff0000',
    'color:green' => '#00ff00',
]);
// escritura de varios datos con una vida útil de 30 días
$cache->mWrite([
    'color:blue'  => '#0000ff',
    'color:red'   => '#ff0000',
], -1);

// escritura (en bruto) de datos a partir de un archivo local
$cache->copyTo('page:home', '/path/to/homepage.html');
// escritura de datos a partir de un archivo local, con una vida útil de una hora
$cache->copyTo('page:home', '/path/to/homepage.html', 3600);

// escritura de varios datos (en bruto) a partir de archivos locales
$cache->mCopyTo([
    'page:home'     => '/path/to/homepage.html',
    'page:admin'    => '/path/to/admin.html',
    'page:products' => '/path/to/products.html',
]);
// escritura de varios datos a partir de archivos locales con una vida útil de 30 días
$cache->mCopyTo([
    'page:home'  => '/path/to/homepage.html',
    'page:admin' => '/path/to/admin.html',
], -1);

4Llamadas específicas

4.1Expiración de la caché

El método setExpiration() se usa para definir el tiempo de caché por defecto. Esto evita tener que definirlo explícitamente cada vez que se escribe un dato en caché.
Recibe un parámetro, que es la vida útil máxima de los datos en caché, expresada en segundos. Por defecto, la duración es de 86400 segundos (24 horas).
Este método devuelve la instancia del objeto de caché.

// definir el plazo de expiración por defecto en una hora
$cache->setExpiration(3600);

// expiración de 5 minutos, seguida de la adición de un dato
$cache->setExpiration(300)->set('aa', 'bb');

Puedes usar el método getExpiration() para saber el tiempo de caché actualmente configurado.

// queremos asegurarnos de que el plazo de expiración sea de al menos 1 hora
$exp = $cache->getExpiration();
if ($exp < 3600)
    $cache->setExpiration(3600);

4.2Gestión de prefijos

Lo que llamamos "prefijos" es una etiqueta que se añade a los nombres de las variables de caché. Su interés reside en poder gestionar todas las variables de caché que tienen el mismo prefijo, para invalidarlas en una sola operación.

El método setPrefix([string $prefix]) se usa para definir el prefijo de las variables que serán procesadas en las llamadas a get() y set() que le sigan. Llamarlo sin parámetros elimina el uso de prefijos.
Devuelve la instancia del objeto de caché.

El método clear(string $prefix) se usa para invalidar todas las variables de caché que tienen el prefijo pasado como parámetro.
También devuelve la instancia del objeto de caché.

Ejemplo de uso:

// definición de un prefijo
$cache->setPrefix('sites');
// añadir variables de caché
$cache->set('A', $siteA);
$cache->set('B', $siteB);
$cache->set('C', $siteC);

// definición de otro prefijo
$cache->setPrefix('articles');
// añadir variables de caché
$cache->set('Y', $articleY);
$cache->set('Z', $articleZ);

// eliminar las variables que pertenecen al primer prefijo
// ("A", "B" y "C")
$cache->clear('sites');

// dejar de usar el prefijo "articles"
$cache->setPrefix();

// recuperar una variable con prefijo
$data = $cache->setPrefix('articles')->get('Z');

Es posible saber el prefijo actual gracias al método getPrefix():

$prefix = $cache->getPrefix();
if ($prefix != 'sites')
    $cache->setPrefix('sites');

4.3Activación / desactivación de la caché

El método disable() se usa para desactivar temporalmente el uso de la caché. Todas las llamadas posteriores no devolverán ningún error, pero no se realizará ningún acceso a la caché.
El método enable() permite reactivar el uso de la caché (después de una llamada a disable(), por ejemplo).
Estos dos métodos devuelven la instancia del objeto de caché.

Ejemplo de uso:

// desactivar la caché
$cache->disable();

// la función anónima se ejecutará sistemáticamente,
// porque la caché está desactivada
$article = $cache->get(
    "article:$articleId",
    function () use ($articleId, $dao) {
        return ($dao->get($articleId));
    }
);

// reactivar la caché y guardar una variable
$cache->enable()->set('name', $value);

El método enable() reactiva la caché que había sido desactivada temporalmente. También devuelve la instancia del objeto de caché.

$cache->enable();

Para saber si la caché está activada o desactivada, puedes usar el método isEnabled(), que devuelve true si la caché está activada, y false en caso contrario.

if (!$cache->isEnabled())
    print("Caché desactivada");