Haciendo del Desarrollo y la Arquitectura Web, ciencia y pasión.

Memcached vs Redis

Algunas veces me he visto en la encrucijada de elegir entre Memcache, Memcached y Redis. A veces la información no es del todo precisa y a veces incluso alguna confusión entre Memcache y Memcached. Al buscar información encontramos que el rendimiento de estos últimos es similar inclinandose a favor de Memcached, aproximadamente un 16%. veamos los siguientes datos.

 

memcache vs memcached: 10000 keys
memcached set: 0.91661500930786
memcached get: 0.86234307289124
memcache set: 1.0546097755432
memcache get: 1.0519700050354

 

Efectivamente los resultados dan un margen a favor de Memcached, así que discutiremos entre Redis y Memcached. Ambos tienen en común que los dos son demonios encargados en almacenar parejas de datos clave-valor en memoria, pudiendo recuperarse desde un cliente. Hasta aquí las similitudes. Memcached es distribuido, es decir podemos tener un conjunto de servidores que atiendan peticiones. Redis puede extender su persistencia a disco como si de una base de datos se tratata, para ser mas precisos, Redis puede considerarse como un motor de base de datos en memoria. Redis además de almacenar parejas permite almacenar en memoria estructuras de datos, como listas, conjuntos o conjuntos ordenados, como dice en su descripcion, Redis es "Memcached on steroids". Sin embargo Memcached es algo más rapido y es distribuido, obteniendo una facil scalabilidad. Redis por su parte no es distribuido, pero permite su expansión por medio de clusters, que lo hace mas complejo de mantener

 
Se trata de dos herramientas maduras con un largo recorrido, usadas por los mas grandes sitios. Memcached fue desarrollado en 2003, inicialmente en Perl y posteriormente migrado a C, por Brad Fitzpatrick. Redis por su parte es algo mas joven, desarrollado en 2009 por Salvatore Sanfilippo. Ambos sistemas son muy populares ya que su implantacion es relativamente sencilla, la inversion en tiempo no es muy alta y, sin embargo, su uso tienen un impacto considerable en el rendimiento de una web.
 
 
Pero vamos a lo que nos interesa: números. Vamos a realizar la prueba más básica que he podido y simila para ambas. Ya que Memcached no dispone de estructuras de almacenamiento nos centraremos en el almacenaje clave-valor. Almacenaremos 10000 claves de 20 caracteres que almacenarán valores Sha1, es decir, valores exadecimales de 40 caracteres.
 
Y, para hacerlo más real, lanzaremos 100 peticiones contra el servidor, con una concurrencia de 10 peticiones, que podría ser perfectamente el tráfico de un servidor mediano, un lunes por la mañana. Para esta prueba usaremos el Apache Benchmark, una herramienta utilísima que nos facilitará el lanzamiento de los servicio y obtencion de los tiempos. 
 
Primero veremos los codigos de la prueba. Básicamente se divide en conexion al servidor, creación de los datos, almacenaje y obetención.
 
Redis:

try {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$c = 10000;
$values = array();
for ($i = 0; $i < $c; $i++) {
$values[sprintf('%020s', $i)] = sha1($i);
}
echo "Redis: $c valores\n";
$start = microtime(true);
foreach ($values as $k => $v) {
$redis->set($k, $v);
}
echo "<br />";
$time = microtime(true) - $start;
echo "redis set: $time\n";
$start = microtime(true);
foreach ($values as $k => $v) {
$redis->get($k);
}
$time = microtime(true) - $start;
echo "redis: $time\n";
} catch (Exception $e) {
die($e->getMessage());
}

Memcached


try {
$m = new Memcached();
$m->addServer('localhost', 11211);


$c = 10000;
$values = array();
for ($i = 0; $i < $c; $i++) {
$values[sprintf('%020s', $i)] = sha1($i);
}

echo "Memcached: $c keys\n";

$start = microtime(true);
foreach ($values as $k => $v) {
$m->set($k, $v, 3600);
}
$time = microtime(true) - $start;
echo "memcached set: $time\n";
$start = microtime(true);
foreach ($values as $k => $v) {
$m->get($k);
}
$time = microtime(true) - $start;
echo "memcached get: $time\n";
} catch (Exception $e) {
die($e->getMessage());
}

Ahora lanzaremos las pruebas. Como he dicho usaremos ab, con 100 peticiones y con una concurrencia de 10. Decir que este equipo donde estoy probando no es el más adecuado. Las pruebas están conviviendo con un entorno gráfico, y posiblemente haya mucho ruido entorpeciendo la prueba, pero es igual para ambas, en concreto es una Ubuntu 16.04.02 sobre un QuadCore con 4 GB de memoria.


✔ ~/proyectos/daniel [master|✚ 6] 
00:17 # ab -n 100 -c 10 http://localhost/testmem/redistest.php
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient).....done


Server Software: Apache/2.4.18
Server Hostname: localhost
Server Port: 80

Document Path: /testmem/redistest.php
Document Length: 87 bytes

Concurrency Level: 10
Time taken for tests: 33.456 seconds
Complete requests: 100
Failed requests: 0
Total transferred: 27700 bytes
HTML transferred: 8700 bytes
Requests per second: 2.99 [#/sec] (mean)
Time per request: 3345.600 [ms] (mean)
Time per request: 334.560 [ms] (mean, across all concurrent requests)
Transfer rate: 0.81 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 3.4 0 15
Processing: 1759 3279 390.5 3307 4001
Waiting: 1759 3278 390.5 3307 4001
Total: 1759 3279 390.0 3307 4001

Percentage of the requests served within a certain time (ms)
50% 3307
66% 3475
75% 3540
80% 3584
90% 3676
95% 3837
98% 3910
99% 4001
100% 4001 (longest request)


✔ ~/proyectos/daniel [master|✚ 6] 
00:27 # ab -n 100 -c 10 http://localhost/testmem/memcachedtest.php
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient).....done


Server Software: Apache/2.4.18
Server Hostname: localhost
Server Port: 80

Document Path: /testmem/memcachedtest.php
Document Length: 94 bytes

Concurrency Level: 10
Time taken for tests: 22.103 seconds
Complete requests: 100
Failed requests: 0
Total transferred: 28400 bytes
HTML transferred: 9400 bytes
Requests per second: 4.52 [#/sec] (mean)
Time per request: 2210.349 [ms] (mean)
Time per request: 221.035 [ms] (mean, across all concurrent requests)
Transfer rate: 1.25 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.2 0 1
Processing: 1235 2161 389.5 2167 3581
Waiting: 1235 2160 389.3 2167 3581
Total: 1236 2161 389.5 2167 3581

Percentage of the requests served within a certain time (ms)
50% 2167
66% 2234
75% 2334
80% 2372
90% 2496
95% 2868
98% 3243
99% 3581
100% 3581 (longest request)



Los resultados como era de esperar dan peticiones mas rapidas a Memcached, nos encontranmos con la peticion mas alta de 4001 ms para Redis frente a los 3581de Memcached. La media  para Memcached es 2167 ms, mientras que Redis tiene una media de 3307ms estamos hablando de mas de 1sg para la misma tarea. 

Parece que la eleccion es clara, Memcached nos da mas rendimiento, pero si necesitamos por otro lado necesitamos mas control para almacenar estructuras entonces nuestro hombre es Redis