Memcached es un almacén de clave-valor en memoria RAM pensado para una sola cosa: guardar resultados costosos de calcular (consultas a base de datos, fragmentos HTML, respuestas de APIs) y devolverlos en microsegundos. No persiste nada en disco ni tiene replicación, así que solo debe contener datos que la aplicación pueda regenerar. En este tutorial instalarás Memcached en Ubuntu 24.04, ajustarás su configuración, lo protegerás frente a accesos externos y lo usarás desde PHP y Python, incluido el almacenamiento de sesiones PHP.

Requisitos previos

Para seguir esta guía necesitas:

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath.
  • Un usuario no root con privilegios sudo.
  • Memoria libre suficiente para la caché que quieras reservar (64 MB bastan para probar; en producción es habitual dedicar entre 256 MB y varios GB).
  • Opcional: PHP 8.3 con PHP-FPM o Python 3 si vas a seguir los ejemplos de integración.

Paso 1: Instalar Memcached

El paquete memcached contiene el servidor y libmemcached-tools añade utilidades de línea de comandos como memcstat para consultar estadísticas:

sudo apt update
sudo apt install memcached libmemcached-tools

El servicio se arranca y se habilita automáticamente. Compruébalo:

sudo systemctl status memcached
● memcached.service - memcached daemon
     Loaded: loaded (/usr/lib/systemd/system/memcached.service; enabled; preset: enabled)
     Active: active (running) since ...

Verifica que escucha solo en la interfaz local, en el puerto 11211:

sudo ss -tlnp | grep 11211
LISTEN 0      1024       127.0.0.1:11211      0.0.0.0:*    users:(("memcached",pid=2481,fd=26))
LISTEN 0      1024           [::1]:11211         [::]:*    users:(("memcached",pid=2481,fd=27))

Paso 2: Ajustar la configuración

Toda la configuración está en /etc/memcached.conf, un fichero con una opción de línea de comandos por línea. Ábrelo:

sudo nano /etc/memcached.conf

Estas son las líneas relevantes. Deja el resto como está:

# Memoria máxima para datos, en MB
-m 512

# Puerto TCP
-p 11211

# Usuario sin privilegios con el que se ejecuta
-u memcache

# Escuchar solo en localhost (IPv4 e IPv6)
-l 127.0.0.1
-l ::1

# Número máximo de conexiones simultáneas
-c 2048

# Hilos de trabajo (normalmente, el número de núcleos)
-t 4

-P /var/run/memcached/memcached.pid

Qué hace cada valor:

  • -m: límite de memoria para los datos. Cuando se llena, Memcached expulsa las claves menos usadas recientemente (LRU); no falla. Reserva un tamaño que el servidor pueda dedicar sin entrar en swap, porque una caché en swap es más lenta que no tener caché.
  • -c: conexiones simultáneas. El valor por defecto es 1024. Súbelo si tienes muchos workers de PHP-FPM o de aplicación conectando a la vez.
  • -t: hilos de trabajo. Por defecto son 4; ajústalo al número de núcleos que quieras dedicarle.
  • -l: direcciones en las que escucha. Mantener 127.0.0.1 y ::1 es lo más seguro cuando la aplicación está en el mismo servidor.

Reinicia el servicio para aplicar los cambios:

sudo systemctl restart memcached

Comprueba que el nuevo límite de memoria está activo. limit_maxbytes se expresa en bytes (512 MB = 536870912):

memcstat --servers=127.0.0.1 | grep -E '^\s*(max_connections|limit_maxbytes|threads):'
	max_connections: 2048
	limit_maxbytes: 536870912
	threads: 4

Paso 3: Probar el servidor a mano

Memcached usa un protocolo de texto, así que puedes hablar con él con nc. Guarda la clave prueba con el valor hola, una caducidad de 60 segundos y léela:

printf 'set prueba 0 60 4\r\nhola\r\nget prueba\r\nquit\r\n' | nc 127.0.0.1 11211
STORED
VALUE prueba 0 4
hola
END

El formato de set es set <clave> <flags> <segundos> <bytes>, seguido del valor en la línea siguiente. Si el tamaño en bytes no coincide con el valor, el servidor responde CLIENT_ERROR bad data chunk.

Paso 4: Proteger Memcached

Memcached no tiene autenticación por defecto. Un Memcached expuesto a Internet permite a cualquiera leer y borrar tu caché, y además se ha usado históricamente para ataques de amplificación. En Ubuntu 24.04 el protocolo UDP ya viene desactivado y el servicio escucha solo en localhost, así que si la aplicación está en el mismo servidor no tienes que hacer nada más.

Si la aplicación está en otro servidor, haz que Memcached escuche en la IP privada y limita el acceso con el cortafuegos. Edita /etc/memcached.conf y sustituye las líneas -l por la IP privada del servidor (your_private_ip):

-l your_private_ip

Reinicia el servicio y permite el puerto 11211 solo desde la IP del servidor de aplicación (your_app_server_ip):

sudo systemctl restart memcached
sudo ufw allow from your_app_server_ip to any port 11211 proto tcp
sudo ufw status
To                         Action      From
--                         ------      ----
11211/tcp                  ALLOW       your_app_server_ip

Paso 5: Usar Memcached desde PHP

La extensión recomendada es memcached (con "d"), basada en libmemcached. Instálala y recarga PHP-FPM:

sudo apt install php8.3-memcached
sudo systemctl reload php8.3-fpm
php -m | grep memcached
memcached

El patrón habitual es cache-aside: se busca la clave en Memcached y, si no está, se calcula el valor, se guarda con una caducidad y se devuelve. Crea un script de prueba:

nano ~/memcached-test.php
<?php
$mc = new Memcached();
$mc->addServer('127.0.0.1', 11211);

function obtenerProducto(Memcached $mc, int $id): array
{
    $clave = "producto:$id";
    $producto = $mc->get($clave);

    if ($mc->getResultCode() === Memcached::RES_NOTFOUND) {
        // Aquí iría la consulta real a la base de datos
        $producto = ['id' => $id, 'nombre' => 'Ejemplo', 'generado' => date('H:i:s')];
        $mc->set($clave, $producto, 300); // 5 minutos
        echo "MISS: guardado en caché\n";
    } else {
        echo "HIT: leído de caché\n";
    }

    return $producto;
}

print_r(obtenerProducto($mc, 42));
print_r(obtenerProducto($mc, 42));

Ejecútalo:

php ~/memcached-test.php
MISS: guardado en caché
Array
(
    [id] => 42
    [nombre] => Ejemplo
    [generado] => 10:15:02
)
HIT: leído de caché
Array
(
    [id] => 42
    [nombre] => Ejemplo
    [generado] => 10:15:02
)

Cuando el dato cambia en la base de datos, invalida la clave con $mc->delete("producto:$id") para que la siguiente lectura la regenere.

Guardar las sesiones PHP en Memcached

Guardar las sesiones en Memcached permite compartirlas entre varios servidores web. Crea un fichero de configuración para PHP-FPM:

sudo nano /etc/php/8.3/fpm/conf.d/30-sesiones-memcached.ini
session.save_handler = memcached
session.save_path = "127.0.0.1:11211"

Recarga PHP-FPM y comprueba el valor desde una página PHP con phpinfo() o con php-fpm8.3 -i:

sudo systemctl reload php8.3-fpm
sudo php-fpm8.3 -i | grep -E '^session.save_(handler|path)'
session.save_handler => memcached => memcached
session.save_path => 127.0.0.1:11211 => 127.0.0.1:11211

Ten en cuenta que Memcached puede expulsar claves cuando se llena o al reiniciarse, lo que cerraría sesiones de usuario. Si eso no es aceptable, reserva memoria de sobra o usa Redis con persistencia para las sesiones.

Paso 6: Usar Memcached desde Python

Para Python, pymemcache es un cliente puro y bien mantenido. Instálalo en un entorno virtual:

sudo apt install python3-venv
python3 -m venv ~/mc-venv
~/mc-venv/bin/pip install pymemcache

Crea un script de prueba:

nano ~/memcached_test.py
from pymemcache.client.base import Client
from pymemcache import serde

client = Client(("127.0.0.1", 11211), serde=serde.pickle_serde)

client.set("usuario:7", {"nombre": "Ana", "plan": "pro"}, expire=300)
print(client.get("usuario:7"))

Ejecútalo:

~/mc-venv/bin/python ~/memcached_test.py
{'nombre': 'Ana', 'plan': 'pro'}

serde.pickle_serde serializa objetos de Python automáticamente. Sin él solo puedes guardar cadenas y bytes.

Paso 7: Supervisar el uso de la caché

Las estadísticas de Memcached indican si la caché está sirviendo de algo. Consulta las más útiles:

memcstat --servers=127.0.0.1 | grep -E '^\s*(curr_connections|get_hits|get_misses|bytes|curr_items|evictions):'
	curr_connections: 3
	get_hits: 18234
	get_misses: 1022
	bytes: 3129856
	curr_items: 4410
	evictions: 0

Cómo interpretarlas:

  • Tasa de aciertos = get_hits / (get_hits + get_misses). En el ejemplo es del 94 %. Si es baja, revisa las caducidades o qué datos estás cacheando.
  • evictions creciendo de forma constante significa que falta memoria: sube el valor de -m.
  • curr_connections cerca del valor de -c indica que debes subir el límite de conexiones.

Si necesitas vaciar la caché completa (por ejemplo, tras un despliegue que cambia el formato de los datos), usa:

memcflush --servers=127.0.0.1

Solución de problemas

  • La aplicación no conecta (Connection refused): comprueba con sudo ss -tlnp | grep 11211 en qué IP escucha el servicio y que coincide con la que usa la aplicación. Si es remota, revisa la regla de UFW.
  • El servicio no arranca tras editar la configuración: consulta sudo journalctl -u memcached -n 50. Un error típico es una IP en -l que no existe en el servidor.
  • Los objetos grandes no se guardan: el tamaño máximo por elemento es 1 MB por defecto. Puedes subirlo con -I 2m en /etc/memcached.conf, aunque normalmente es mejor no cachear objetos tan grandes.

Conclusión

Ya tienes Memcached instalado en Ubuntu 24.04, limitado a la memoria que has decidido, protegido frente a accesos externos y conectado a PHP y Python, con las estadísticas necesarias para saber si la caché es eficaz. Como siguientes pasos, puedes activar OPcache para acelerar la ejecución de PHP, ajustar los pools de PHP-FPM o medir la mejora con Apache Bench antes y después de introducir la caché.