Desmitificando Memcached (I)

Me he decidido a hacer este post debido a la cierta oscuridad que hay sobre memcached en muchos entornos de desarrollo web. En webs de alto tráfico está instalado (y de hecho gracias a ello las webs aguantan) y muchas veces los desarrolladores lo usan sin entender realmente qué está sucediendo.

Y en el mundillo freelances y pymes, donde se suele tener servidores compartidos no es que esté precisamente muy extendido el uso de este u otros sistemas de cacheado. Vamos pues a intentar aportar algo de luz al respecto.

En el mundillo PHP, veremos que se usa indistintamente las palabras memcache y memcached sin tener muy claro cuál es la correcta. Para aclararlo, en resumen:

– Memcached: Es un sistema distribuido de propósito general para caché que se instala en un servidor y funciona como un servicio más de la máquina, escuchando por un puerto que configuramos. (Ver Wikipedia). Este servidor es completamente independiente de PHP y se puede usar en general desde cualquier lenguaje de programación que tenga librerías para interactuar con él.

– Librería memcache de PHP (Ver PHP.net): Es una librería ya algo antigua que nos encapsula el acceso a Memcached. Sirve como primera aproximación y es muy fácil de instalar y activar pero no aprovecha todo el potencial de memcached.

– Librería memcached de PHP (Ver PHP.net): Es una librería bastante más moderna, algo complicada de instalar en según qué distribuciones Linux (pues requiere compilar las librerías libmemcached y la propia librería si queremos habilitar serializadores especiales como IgBinary) pero que nos da mejor rendimiento y aprovecha mejor las posibilidades de memcached.

Hechas estas aclaraciones, vamos a explicar qué es y sobretodo qué no es memcached y sus problemas (que también los tiene).

¿Qué es memcached? ¿Para qué nos puede servir?

Como hemos dicho, memcached es un sistema de cacheado de propósito general. Cachear es algo que en aplicaciones con poca actividad no nos supondrá ningún beneficio pero que en entornos de alta disponibilidad es clave para asegurar que una subida de actividad no nos dejará sin servicio. El concepto es simple, si algo cambia poco, guárdatelo ya procesado y listo para servir sin tener que acceder a la BBDD y procesar esos datos. Aunque una conexión a BBDD y su query vaya rápido, es mucho más rápido leer directamente de disco (algunos sistemas básicos de caché hacen eso, precalcular cosas y dejarlas en fichero ini o xml) y aún más rápido guardarlo en un buffer de memoria (como hacen Memcached o también por ejemplo APC, del cual hablaré en próximos posts y cuya mejora respecto a memcached es que los datos no se guardan serializados).

En webs como Privalia o otras de volúmenes similares tenemos datos que cambian poco y se piden mucho, como por ejemplo los detalles de los productos, los detalles de las campañas, etc… Parece lógico almacenar estos datos en un sitio intermedio durante un periodo razonable de tiempo para acelerar drásticamente el acceso a los mismos sin necesidad de entrar a MySQL.

También es bastante habitual guardar los datos de sesión en memcached en vez de en disco (que es la configuración por defecto de PHP). Con ello, podemos tener una configuración de servidores con múltiples frontales Apache balanceados sirviendo el mismo código y todos tirando de memcached para las sesiones sin tener que configurar una carpeta de disco compartida por todos. De hecho, es posible configurar PHP para que directamente use memcached de forma transparente para las sesiones y nos olvidamos de este tipo de problemas.

¿Cómo funciona?

Todas las librerías de memcached tienen los siguientes métodos básicos

Connect: Donde básicamente pasamos ip, puerto y alguna cosilla más
SetData: Donde pasamos los datos a guardar (podemos pasar directamente arrays y objetos que la propia librería se encarga de serializar), una clave alfanumérica para identificarlo y el tiempo de cacheado.
GetData: Donde pasamos la clave a recuperar, y nos devuelve los datos unserializados.
FlushData: Donde pasamos la clave a eliminar (esto puede servir para que un cambio en backoffice elimine datos cacheados ya incorrectos)
FlushAll: Elimina todas las claves de memcached.

Y… poquito más. Bien es cierto que en las nuevas versiones podemos configurar N servidores, definir el porcentaje de peticiones que irán a uno u otro, configurar el serializador, etc… pero la base es esta.

La estrategia es sencilla y tiene 3 pasos:
– Justo antes de hacer una query a BBDD cuyo resultado cambia poco, generamos una key y miramos si el dato ya esta cacheado.
– Si lo está, no hacemos la query y devolvemos los datos cacheados.
– Si no lo está, hacemos la query, cacheamos los datos y los devolvemos.

Problemas de memcached

Sí, no todo son ventajas y hay que tenerlas en cuenta. Cosas con las que me he encontrado serían las siguientes:

– Por cada clave solamente se permite almacenar 1 Mb de datos serializados. Esto es una auténtica burrada y cabe medio quijote pero según lo que queramos almacenar podemos pasarnos. Lo cachondo del caso es que no salta excepción sino que simplemente devuelve false.

– El servidor de memcached tiene definida una memoria de uso. Si cacheamos muchas cosas, se puede producir un overflow y las claves más antiguas empiezan a expirar para hacer sitio a las nuevas. Mucho cuidado pues con configurar correctamente esto.

– En alta escalabilidad, hasta que está todo cacheado puede darse el caso de muchas peticiones intentando cachear lo mismo simultáneamente. Este fenómeno es conocido como cache storming y aunque dura poco podemos tener problemas en aplicaciones donde de golpe la demanda aumenta drásticamente.

– No se pueden hacer querys para recuperar las keys almacenadas ni un rango de las mismas. Es decir, mucho cuidado con elegir las keys en los setData ya que nos podemos encontrar con no saber regenerarlas y por tanto no poder expirar keys concretas.

– Si no dimensionamos bien la aplicación, podemos estar haciendo muchos setData y pocos getData (porque el tiempo de expiración es muy bajo o porque cacheamos datos de poca consulta).

– Si confiamos en que memcached aguantará la carga y no optimizamos la aplicación, el día que se cae memcached, adios aplicación web en escasos minutos.

– Si los datos a cachear son muy grandes, la serialización de los mismos se vuelve muy costosa. Esto es especialmente grave con la vieja librería memcache y subsanado en parte con memcached+igbinary. Siempre irá más rápido que una query, especialmente si hacemos varias joins, pero tal vez la ganancia no sea tan grande como esperamos.

– Memcached no lleva autenticación. Es decir, cualquiera con acceso al servidor, si conoce las keys puede recuperar nuestros datos. Debido a esto, raramente está instalado en servidores compartidos.

¡Todos los que podáis, a usar memcached!

Teniendo en cuenta todo lo que he comentado, si decidimos tirar de memcached veremos que nuestra aplicación web aumenta mucho en tiempo de respuesta y capacidad de servicio sin hacer mucha cosa más que modificar algunas funciones del modelo para intentar sacar los datos de memcached antes de ir a la base de datos.

Es muy sencillo de instalar el servidor y la librería memcache básica y con una pequeña prueba de stress con Jmeter o similar veremos cómo mejora la cosa.

Esto es todo por hoy, en próximos posts ejemplos de código, ventajas e instalación de Memcached y Igbinary y APC.

You may also like...

11 Responses

  1. Albert Casademont says:

    Ojo! Memcached guarda los datos en RAM, no en disco eh? Parece que al nombrar APC no quede claro que Memcached también usa RAM

  2. Ricard Clau says:

    Cuando lo escribía estaba pensando en que APC cachea sin serializar y Memcached serializado, de ahí el mejor rendimiento, y es cierto que no lo he escrito así y puede llevar a engaño jeje, corregido!!!

  3. Raul says:

    Hablando de optimizaciones…
    ¿Conexiones a DB persistentes o no persistentes? ¿Qué me dices?

  4. Ricard Clau says:

    http://php.net/manual/es/features.persistent-connections.php

    Sin dudarlo, NO-persistentes. Con las conexiones actuales y el diseño interno de MySQL5, tendrías muy poca ganancia y muchos problemas potenciales.

    Hoy en día el coste de establecer la conexión no es demasiado grande, la verdad.

    Lógicamente esto cambia si tienes el MySQL muy “lejos” a nivel de red de los Apaches, pero eso ya es más un tema de mal diseño de la arquitectura del sistema.

  5. Jorge says:

    Hola Ricard, interesante artículo que aclara bastante del asunto, porque es materia algo confusa. En mi caso, el follón mental venía porque el daemon y la librería (al menos una de ellas, justo la que no puedo instalar), se llaman de la misma forma, memcached.

    Ok, quería preguntarte a ver si por casualidad puedes orientarme. Tengo una instancia EC2 en Amazon, con AMI Linux (en principio es un Red Hat/CentOS modificado). He conseguido instalar el servicio memcached sin problemas.

    Por otra parte, ejecutando yum install php-pecl-memcache y editando /etc/php.d/memcache.ini consigo instalar la libreria memcache.so

    Lo que no consigo instalar es la librería memcached. He ejecutado yum install libmemcached.i686 pero ahora debería haber algo similar a php5-memcached para Ubuntu, pero no lo encuentro para Red Hat/CentOs. ¿Tienes idea de como instalar esta librería?

    Mas que nada porque en todas partes estoy leyendo que es más eficaz trabajar con la librería memcached que con memcache. (Queda claro que el servicio al que ambas llamarán siempre será memcached).

    Gracias y saludos 🙂 Por cierto, ya me contarás como te manejas con Kohana, yo me quedé en CodeIgniter por la documentación.

  6. Hola Jorge

    En el trabajo yo lo conseguí instalar todo con CentOS 5.4.
    Te cuento, la librería memcached la descargué en primera instancia con pecl (pecl install memcached). Esto funcionaba bien y se instaló correctamente, el problema es que para habilitar IgBinary hay que recompilar la librería añadiendo un parámetro.

    Tengo el blog algo abandonado 🙄 y mi próximo artículo iba a ser un poco sobre esto que comentas.

    En mi caso, me guié por lo que pone en http://www.ggtai.com/content/php-libmemcached-memcached-igbinary.

    Además, en el trabajo tenemos PHP5.2 y me petaba la compilación habilitando IgBinary porque había un problema con las librerías JSON, tuve que modificar un archivo C, vamos fue un poco pitoste.

    En cuanto a rendimiento, por lo menos en mi entorno la librería memcached es un poco más lenta que la memcache, pero al habilitar igbinary, el serializado es mucho más rápido (cerca de un 30% de diferencia de velocidad en arrays grandes) y ahí recuperas bastante.

    Espero que te sirva, seguramente si usas una CentOS/RedHat con paquetes más actualizados y PHP5.3 no tendrás tantos problemas, ya me cuentas 😉

    En cuanto a Kohana, si conoces CodeIgniter para empezar son bastante parecidos pero está mucho mejor programado en Orientación a Objetos. CodeIgniter hasta que hace poco salió la versión 2 aún era compatible con PHP4, pasaba los objetos por referencia (que en PHP5 no es necesario), etc… Pero es verdad que en documentación Kohana es un desastre 🙂

    Saludos!

  7. Jorge says:

    Ok, gracias por responder tan rápido, echaré un vistazo a eso que me cuentas y si no lo consigo me quedaré con memcache. Si, lo de kohana con la documentación es un pelín complicado… y yo necesito leer mucho para enterarme, la verdad. Gracias por todo y probaré lo de Igbinary, no lo había oído nunca… esto es un no parar de estudiar, ya sabes 😉

  8. Luis says:

    😳 Hola deseo hacer una enorme y ignorante consulta para personas de tan avanzada de este foro soy totalmente novato en el tema de memcached y demas , est0y manejando un servidor mikrotik para distribuir internet por wifi , pero ahora me eh metido a investigar como hacer cache de paginas web dinamicas y de actualizacion constante ( youtube, facebook,update de windows , nod 32, etc) me han hablado del famoso thundercache pero no lo veo tan aceptable y sobre todo q no quiero hacer lo mismo q todos hacen asi q me eh metido a investigar otro servidor de paginas web dinamicas para mi red y mis clientes , mi pregunta es este sistema memcached me serviria para montar un servidor y aligerar mas mi red de internt , podria implementarlo para almacenar en ese server las web dinamicas con las correspondientes actualizaciones q se dean , ustedes q me recomendaria y cual so en unix o linix o que deberia hacer , muchisimas grs por su respuesta y su orientacion de antemano y saludos al dueño de este tutorial esta bueno q lo entendi asi sea un novato dejo mi mail para ver si hay alguna persona de buena voluntad q me pueda c0ntactar y darme una manito en mi aventura jeje muchsimas grs

  1. 24/05/2011

    […] ser que el post anterior de Memcached ha tenido bastante éxito o por lo menos hay bastante gente que busca este tema en Google, así que […]

  2. 19/09/2012

    […] If you dont have the knowledge of installing the scripts you want on your website, SiteDuct offers fast script installation service. Read More… […]

  3. 10/02/2013

    […] We sell all your favorite hookah supplies. Hookah charcoal, and hookah accessories. We got you covered. Original Post: http://www.ricardclau.com/2011/03/desmitificando-memcached-i/ […]