Acelera tu sitio web con Memcached
Spanish (Español) translation by Steven (you can also view the original English article)
Tu último sitio web PHP/MySQL finalmente está en línea. Y es asombroso. Pero no es tan rápido como quisieras, debido a las muchas consultas SQL que se ejecutan cada vez que se genera una página. Y por encima de eso, tienes la sensación de que no se escalará bien bajo cargas pesadas. Y probablemente tengas razón.
En este tutorial, veremos cómo puedes mejorar en gran medida la capacidad de respuesta de tu sitio web y ayudarlo a escalar para manejar muchos visitantes simultáneos, mediante la implementación de una capa de caché entre tu código y tu base de datos. La buena noticia es que es bastante fácil y se puede hacer en unos minutos.
Introducción a Memcached


Memcached es un sistema de almacenamiento en caché de datos en memoria de alto rendimiento.
Los sitios web y las aplicaciones web modernas utilizan una gran cantidad de datos, y no es raro contar hasta 20 o incluso 30 consultas SQL en una sola generación de página. Multiplica esta cantidad por una gran cantidad de visitantes y, a menudo, obtendrás una base de datos sobrecargada y páginas que tardan unos segundos en generarse y enviarse al cliente.
La herramienta que vamos a utilizar hoy para mejorar el rendimiento se llama Memcached. Es un sistema de almacenamiento en caché de datos en memoria de alto rendimiento. O, para decirlo de otra manera, una aplicación muy rápida que se ejecuta en tu servidor y utiliza una fracción de la memoria disponible para almacenar una matriz asociativa de datos. Puedes pedirle a Memcached que haga dos cosas:
- Almacene el valor
Vcon la claveK - Obtenga el valor
Valmacenado con la teclaK
Esto parece minimalista, pero hay mucho que puedes hacer gracias a estas dos características, como veremos muy pronto. De hecho, Memcached puede hacer algunas cosas más, pero todas están vinculadas a almacenar o recuperar datos.
Instalar Memcached en distribuciones modernas de Linux es bastante simple:
- Ubuntu:
sudo apt-get install memcached - Gentoo:
sudo emerge install memcached - Redhat:
sudo yum install memcached
Una vez instalado, Memcached se iniciará automáticamente cada vez que se inicie el servidor. Puedes establecer la cantidad de memoria reservada para Memcached, junto con otras opciones, en el archivo de configuración (/etc/memcached.conf). 64Mb se asignan de forma predeterminada. El archivo de configuración también contiene la dirección IP y el puerto al que estará vinculado Memcached. Los valores predeterminados (127.0.0.1 y 11211) están bien para una configuración estándar.
Accediendo a Memcached desde PHP
Queremos almacenar y obtener datos de tus scripts PHP. Esto significa que vamos a necesitar una forma de conectarnos a Memcached desde PHP. Para eso, vamos a instalar la extensión "Memcache" para PHP. Como es una extensión PECL, es muy fácil de instalar con el "pecl" escribiendo el siguiente comando:
1 |
sudo pecl install memcache |
Hay dos extensiones PHP relacionadas con Memcache: "Memcache" y "Memcached" (observa la "d" en la segunda). Ambos son muy similares, pero el primero ocupa menos espacio. En este tutorial, usaremos el Memcache más ligero. Una vez instalada, esta extensión debería estar habilitada y las funciones relacionadas con Memcache ahora deberían estar disponibles para tus scripts PHP.
¿Cómo funciona el almacenamiento en caché?
Nuestro trabajo aquí se basa en los siguientes supuestos:
- obtener datos de la base de datos requiere recursos (CPU + i/o)
- obtener datos de la base de datos lleva tiempo
- a menudo obtenemos los mismos datos una y otra vez
También queremos almacenar nuestros datos de una manera que nos permita obtenerlos de manera eficiente.
En términos generales, queremos guardar nuestros datos en un entorno persistente (nuestra base de datos MySQL, por ejemplo). Pero también queremos almacenar nuestros datos de una manera que nos permita recuperarlos de manera eficiente, incluso si el almacenamiento no es persistente. Entonces, al final, tendremos dos copias de nuestros datos: una almacenada en MySQL y la otra almacenada en Memcache.
Estos son los pasos que debemos seguir para que esto suceda:
- Cada operación de escritura (
INSERTyUPDATEen SQL) se realizará tanto en MySQL como en Memcached - Cada operación de lectura (
SELECTde SQL) se realizará en Memcached y volverá a MySQL en caso de error
En este punto, probablemente veas qué partes de tu código necesitan ser modificadas: partes donde escribes datos y partes donde lees datos. Si tu código PHP está bien estructurado, deberías haber envuelto tu código de acceso a datos en funciones o, incluso mejor, clases. Si es así, la actualización de tu sitio debería ser muy rápida. Si no, es posible que tengas un poco más de trabajo.
Conectando a nuestro servidor de caché
En primer lugar, creemos una conexión a nuestro servidor Memcached. Aquí está el código que debes usar, al principio de tus scripts PHP:
1 |
// Connection constants
|
2 |
define('MEMCACHED_HOST', '127.0.0.1'); |
3 |
define('MEMCACHED_PORT', '11211'); |
4 |
|
5 |
// Connection creation
|
6 |
$memcache = new Memcache; |
7 |
$cacheAvailable = $memcache->connect(MEMCACHED_HOST, MEMCACHED_PORT); |
En este punto, hemos establecido una conexión con nuestro servidor Memcache. Puede que haya fallado, pero lo sabremos gracias a la variable $cacheAvailable.
Almacenamiento de datos en nuestro caché
Vamos a sumergirnos en el almacenamiento de datos. Vamos a tomar un ejemplo para aclarar las cosas: una tienda online. Tenemos un script llamado edit_product.php cuyo propósito es guardar los datos de un producto en nuestra base de datos. Cada uno de nuestros productos tiene la siguiente información:
- id
- name
- description
- price
En algún momento de nuestro código edit_product.php, ejecutamos una consulta SQL de tipo INSERT o UPDATE cuyo propósito es escribir los datos de este producto en nuestra base de datos MySQL. Podría verse así:
1 |
// We have validated and sanitized our data
|
2 |
// We have escaped every risky char with mysql_real_escape_string()
|
3 |
// Now we want to save it into our database
|
4 |
$sql = "INSERT INTO products (id, name, description, price) VALUES ($id, '$name', '$description', $price)"; |
5 |
$querySuccess = mysql_query($sql, $db); |
Como mencioné anteriormente, queremos almacenar nuestros datos tanto en nuestra base de datos MySQL como en el servidor Memcached. Así es como vamos a proceder:
1 |
// We have validated and sanitized our data
|
2 |
// We have escaped every risky char with mysql_real_escape_string()
|
3 |
// Now we want to write them to our database :
|
4 |
$sql = "INSERT INTO products (id, name, description, price) VALUES ($id, '$name', '$description', $price)"; |
5 |
$querySuccess = mysql_query($sql, $db); |
6 |
|
7 |
// We have written our data into our database
|
8 |
// Now let's store the product name, description and price into our cache
|
9 |
// The method "set" tells our Memcached server to store the data associated to a specific key
|
10 |
if ($querySuccess === true) |
11 |
{
|
12 |
// We build a unique key that we can build again later
|
13 |
// We will use the word 'product' plus our product's id (eg. "product_12")
|
14 |
$key = 'product_' . $id; |
15 |
|
16 |
// We store an associative array containing our product data
|
17 |
$product = array('id' => $id, 'name' => $name, 'description' => $description, 'price' => $price); |
18 |
|
19 |
// And we ask Memcached to store that data
|
20 |
$memcache->set($key, $product); |
21 |
}
|
En este punto, tanto nuestra base de datos como la caché contienen los datos de nuestros productos.
Obteniendo datos de nuestro caché
En caso de que nuestro caché no esté disponible, queremos recurrir a MySQL.
Ahora obtengamos nuestros datos. En el mismo ejemplo, digamos que nuestra tienda en línea tiene un script llamado product.php que muestra un producto específico. Accediendo a la página product.php?id=12 mostrará el producto cuyo identificador es 12.
En algún momento de nuestro código product.php, ejecutamos una consulta SQL de tipo SELECT cuyo propósito es obtener los datos de un producto de nuestra base de datos MySQL. Podría verse así:
1 |
// We have validated and sanitized our data
|
2 |
// We have escaped every risky char with mysql_real_escape_string()
|
3 |
// Now we want to read from our database :
|
4 |
$sql = "SELECT id, name, description, price FROM products WHERE id = " . $id; |
5 |
$queryResource = mysql_query($sql, $db); |
6 |
$product = mysql_fetch_assoc($queryResource); |
Como dijimos anteriormente, queremos obtener sus datos de nuestro servidor Memcached si es posible, porque es más rápido que obtenerlos de MySQL. Pero en caso de que no se pueda acceder a nuestro servidor de caché, o si simplemente no almacena los datos que necesitamos, queremos recurrir a MySQL. Así es como vamos a proceder:
1 |
// Initialize our $product variable
|
2 |
$product = null; |
3 |
|
4 |
// First we check that our cache server is available
|
5 |
// The $cacheAvailable variable was initialized when we connected to our cache server
|
6 |
if ($cacheAvailable == true) |
7 |
{
|
8 |
// We build the key we associated to our product data
|
9 |
$key = 'product_' . $id; |
10 |
|
11 |
// Now we get the data from our cache server
|
12 |
$product = $memcache->get($key); |
13 |
}
|
14 |
|
15 |
// do we need to access MySQL ?
|
16 |
if (!$product) |
17 |
{
|
18 |
// In case we do...because our $product variable is still null
|
19 |
// We have validated and sanitized our data
|
20 |
// We have escaped every risky char with mysql_real_escape_string()
|
21 |
// Now we want to read from our database :
|
22 |
$sql = "SELECT id, name, description, price FROM products WHERE id = " . $id; |
23 |
$queryResource = mysql_query($sql, $db); |
24 |
$product = mysql_fetch_assoc($queryResource); |
25 |
}
|
En este punto, hemos obtenido los datos que necesitábamos. Lo más probable es que se haya hecho desde nuestro caché, pero podría ser de MySQL si el caché no se llenó o no se pudo acceder a él por alguna razón.
Conclusión
Hemos visto cómo Memcached se puede utilizar para acelerar tu sitio web y limitar la carga de tu base de datos. Nuestro ejemplo anterior se basó en PHP y MySQL porque estas tecnologías se implementan ampliamente, pero este principio es universal y funciona de la misma manera con muchas otras tecnologías: C/C++, Java, Python, Ruby, Perl, .Net, MySQL, Postgres, Erlang, Lua, Lisp, Cold Fusion, Ocaml e io se enumeran junto con PHP en la wiki oficial de Memcached.
Como mencioné anteriormente de manera breve, Memcached proporciona más funciones que los métodos simples de configuración y obtención que hemos visto anteriormente. Dos características adicionales útiles son las actualizaciones de incremento/decremento y la capacidad de establecer un tiempo de vencimiento para un dato almacenado específico. Ambos están disponibles en PHP, junto con algunos otros, como puedes ver en la documentación de Memcache.
Diviértete implementando esto en tus sitios web y disfruta de la mejora del rendimiento —gratis—. Muchas gracias por leer y avísame en los comentarios a continuación si tienes alguna pregunta.



