Uso de memcached desde Java

Tal vez algunos hayan escuchado de memcached, un software que provee un cache en memoria para cualquier cosa que quieran almacenar de manera temporal. El concepto detrás de este software es muy simple: es como tener un mapa gigante, al cual ustedes le pasan una llave, un valor y una duración o fecha de expiración. El software almacena el valor, que será accesible al pedirlo por la llave bajo la cual fue almacenado; cuando la fecha de expiración pase, el cache ya no devuelve el valor para esa llave, porque ya expiró.

Este software se ha vuelto muy utilizado en varias aplicaciones web por las siguientes razones:

  • Es muy fácil de instalar (en Linux/*NIX al menos) y configurar.
  • Meter valor al cache y leerlos es bastante rápido, incluso cuando hay varias miles de llaves vigentes.
  • Se puede utilizar de manera distribuida, teniendo varias instancias en distintos equipos y ninguna tiene que saber de la existencia de las otras; el cliente es quien hace la distribución de valores a las distintas instancias.
  • Hay clientes para varios lenguajes y plataformas: Ruby, C, PHP, y por supuesto Java.

Muchos desarrolladores se han topado con problemas de este tipo: hay valores que se leen de la base de datos, que se obtienen de manera muy específica, y que se tienen que estar leyendo con mucha frecuencia. Cuando la frecuencia de lectura de dichos valores rebasa por mucho la frecuencia con que los mismos valores cambian, conviene usar un cache en memoria. Pero un cache en memoria dentro de la misma aplicación puede aumentar bastante de tamaño y se convierte en un problema de escalabilidad. Con memcached esto se resuelve porque se puede tener un servidor dedicado con bastante memoria (o varios servidores incluso), o bien tener varias instancias repartidas en los equipos disponibles, cada una usando poca memoria (el default es 64MB, pero se pueden configurar para usar 128MB, 256MB o más).

Un ejemplo concreto: en un sitio de comercio electrónico, siempre se tiene el carrito de compras. Este carrito no es otra cosa que una lista de los items que un usuario planea comprar. En una aplicación Java, una solución sencilla es manejar una lista en la sesión de la aplicación. Pero qué pasa si es un sitio donde no se están manejando sesiones porque se tienen demasiados usuarios y entonces se usan puras cookies? Hay que agregar una cookie para el carrito. Pero esa cookie puede crecer bastante si el usuario agrega muchos items al carrito, y aunque sea compacta, ese dato adicional por usuario, cuando son muchos usuarios entrando a un sitio, incrementa mucho el tráfico de red.

Una opción entonces es guardar el carrito en base de datos, con un registro por usuario. Pero entonces hay que hacer un proceso que limpie esa tabla, borrando los carritos que ya tienen mucho tiempo, para evitar que se llene demasiado con datos que ya no se van a utilizar.

Otra opción es usar memcached para almacenar el carrito de cada usuario. Cada carrito se almacena con una llave que es el identificador del usuario, y puede tener un tamaño variable pero generalmente no pasará de un par de kilobytes. De modo que se pueden configurar un par de instancias de memcached para almacenar ahí puros carritos de compras, se les puede poner una duración de un día, que comienza a contarse desde que se almacena el valor por primera vez o cuando se modifica. De este modo, un usuario puede tener "vivo" su carrito si todos los días lo modifica; incluso podemos hacer algo para extender la duración del valor en el cache si es que el usuario regresa diario aunque sea a ver el carrito, sin modificarlo.

Desde Java, una manera sencilla de utilizar memcached es por medio de la biblioteca spymemcached. Su uso es muy simple, sólo hay que crear una instancia de MemcachedClient e indicarle cuáles son las instancias de memcached a las que debe conectarse; con esto tendremos acceso al cache distribuido que ya hemos configurado previamente.

Posteriormente, sólo queda almacenar valores y leerlos, todo por medio del mismo objeto MemcachedClient. La lectura y escritura es de manera similar a un mapa. La escritura se realiza de manera asíncrona, es decir que el método que invocamos, realmente encola una tarea para escribir al memcached, en un threadpool.

 

Cuando hay varias instancias de memcached disponibles, el cliente determinará en cuál almacenar el valor (y de la misma manera, en cuál instancia buscarlo para obtenerlo), según unos algoritmos definidos por los creadores de memcached, basados en un hashing de la llave.

Se pueden tener varias aplicaciones utilizando el mismo cache, esa es otra de las ventajas: una aplicación puede buscar primero un valor en el cache, al no encontrarlo lo busca en la base de datos y lo pone en el cache, y la segunda aplicación cuando busque en el cache encontrará el valor, ahorrándose una consulta a la base de datos. Pero es importante que todos los clientes de memcached tengan su lista de servidores memcached en el mismo orden, para que almacenen los valores en el mismo lugar; de lo contrario, una aplicación puede almacenar en valor1 en el servidor1 y otra aplicación no lo encontrará porque busca valor1 en el servidor2 (y puede terminar almacenando valor1 en servidor2, duplicando de manera innecesaria los valores en el cache).

Los casos de uso de memcached son muy variados. En general, es muy útil para almacenar valores que se obtienen de base de datos pero que son leídos con mucha frecuencia, por una o varias aplicaciones. Pero algo es muy importante: memcached no es un sustituto de base de datos. Debe utilizarse únicamente para almacenamiento temporal; el caso típico es buscar en el cache un valor, y si no se encuentra, entonces buscar en la base de datos y lo que se obtenga se almacena en memcached, para que ya la próxima vez que se busque, se tenga a la mano en el cache y no haya que buscarlo en base de datos.

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de benek

Instancias

Sumamente interesante.

Tengo dos preguntas...

¿Como por qué querrías varias instancias de memcached en un solo equipo en lugar de una sola instancia?

Y...

¿Los valores se guardan en la RAM, o en una mini base de datos de memcached?

¡Buen post!

Imagen de ezamudio

RAM

Memcached es puramente RAM, no usa disco. Es como si tuvieras un HashMap de Java, gigante, donde almacenas miles y miles de valores, cada uno bajo una llave y con su propia expiración.

No querrías tener varias instancias de memcached en un solo equipo, no da ningún beneficio. Sin embargo, si no puedes tener un servidor dedicado a memcached pero tienes varios equipos disponibles, puedes echar a andar varias instancias, una en cada equipo, cada una utilizando poca memoria (digamos unos 64 o 128MB, que no es la gran cosa cuando hablamos de servidores). De ese modo tienes un cache grande, compuesto de varias instancias con poca memoria, distribuidas en varios equipos.

Imagen de jmanuel_ll

Interesante

Muy intereante para aplicaciones que utilizan variables de sesión o de instancia como comentas en el mismo artículo con el ejemplo del carrito de compras.

En nuestro caso (empresa) tenemos una aplicación que consume una cantidad considerable de recursos/usuario(+5k de usuarios en picos ) y más con el tiempo de validez de la sesión (2.59hrs). Me parece una alternativa muy interesante para una alta demanda de la aplicación. Sólo me llaman dos puntos, el medio de transmisión es la red y por tanto debe de haber una alta disponibilidad en la misma

En fin, tengo un par de preguntas que si podrías apoyarme a aclarar por tu avance en el tema, estaría genial:
-Mencionas que sólo RAM, pero utiliza una nueva instancia de Java, se puede instanciar o en donde esta instanciada la aplicación?
-Es considerable el consumo de ancho de banda con cada lectura/escritura en el caché remoto?
-Existe la habilidad de manejar clustering de caché para aumentar la disponibilidad como contingencia?

Muchas gracias por la información y daré inicio a documentarme para iniciar las pruebas respectivas =).

Saludos!

Muy buena @ezamudio. Les para

Muy buena @ezamudio. Les dejo para enriquecer el tema y a los playeros, les dejo la documentación de play! para utilizar memcached. Saludos!

Imagen de ezamudio

jmanuel

No entendi bien tu primera pregunta. Pero la cosa es que instalas memcached en uno o varios equipos y ahi lo pones a correr, indicándole cuánta memoria ocupar. Lo que puse de código es para instanciar un cliente de memcached, es el objeto que se conecta por red a las instancias de memcached disponibles.

Tal vez sea bueno aclarar que cuando hablo de instancias me refiero a procesos memcached. Un proceso memcached corriendo en un servidor es una instancia de memcached. Nada que ver con OOP. Puedes tener varios procesos memcached corriendo en varios equipos y cuando creas tu cliente (una instancia de MemcachedClient en Java) se conecta a todos esos procesos. El tráfico en la red depende de lo que almacenes en memcached. No sé si por clustering te refieres a tener varios procesos de memcached pero pues ya mencioné que puedes tener un proceso por equipo, si lo pones en varios equipos, tienes una especie de cluster rudimentario. Si uno de los procesos truena pues el cliente ya no puede conectarse ahí y normalmente lo que hace es almacenar sus datos en otra instancia (o nodo o como quieras llamarle). Esos detalles los puedes ver en la documentación de spymemcached, la liga está en el artículo.

Es muy importante que cuando uses memcached lo hagas considerando que puede estar o no estar disponible; es simplemente una manera de optimizar acceso a datos temporales, no debe ser algo esencial para que tu aplicación funcione.

Buena info @ezamudio

Siempre hay algo nuevo que aprender.

0_o

Imagen de jmanuel_ll

ezamudio

Gracias, muy clara tu respuesta. A documentarse entonces. =)

Imagen de Shadonwk

seria algo asi, como un

seria algo asi, como un cluster de maquinas viejitas, con el fin de utilizar la memoria RAM disponible en cada una.

Imagen de ezamudio

Exactamente

Así es Shadonwk, puedes usar varios equipos viejos, o como decía, poner varios memcached a correr en los servidores que tienes disponibles, de modo que no necesites uno dedicado, porque el proceso memcached en un server va a ocupar poca memoria y poco CPU, pero se compensa que tengas varios.

Imagen de Shadonwk

se ve interezante, hace un

se ve interezante, hace un par de años creo (o menos) implementamos un cluster pero para utilizar los procesadores de dichos equipos, y pues quedaron varias maquinas... si tengo tiempo, creo que le echare un ojo a memcached y porque no talvez implementarlo...

Imagen de sixtocontreras

Aplicar memcached

Hola buenas noches, mira tengo una inquietud acerca de memcached, quisiera aplicarlo en java pero no se por donde arrancar debo instalar algun software o es por medio de .jar.

gracias de atemano por tu ayuda.

ejemploMemcached

Hola, quisiera saber si me podria ayudar con un ejemplo sencillo de caches distribuidas entre dos computadoras???estoy tomando en la universidad la materia de programacion distribuida y necesito solo replicar algun ejemplo que demuestre la utilidad de este tipo de caches muchas gracias....

Imagen de paranoid_android

Muy bueno

Muy buen post

Imagen de ezamudio

cache distribuido

sixtocontreras: Con memcached, simplemente debes ejecutar una instancia en cada equipo. Puede ser uno solo, dos, tres, los que quieras; no se comunican entre ellos, porque el cliente de memcached en tu aplicación es el que decide cómo repartir los datos entre las instancias, solamente debes configurarlo para indicarle dónde están, y si usas varios clientes que van a compartir datos, todos deben tener la misma configuración, es decir, la lista de caches en el mismo orden.

PedroG08, memcached está escrito en C y puedes bajar el fuente y compilarlo, o si usas alguna distro de Linux seguramente hay un paquete que puedes instalar con el manejador correspondiente (yum, apt, etc). En este post describo cómo utilizar memcached desde una aplicación Java, por medio de la biblioteca spymemcached.