Utilice Memcached para el rendimiento empresarial de Java, Parte 1: Arquitectura y configuración

Desarrollada por Danga Interactive para mejorar el rendimiento del sitio en LiveJournal.com, la arquitectura distribuida de Memcached admite hoy la escalabilidad exponencial de las aplicaciones web sociales como Twitter, Facebook y Wikipedia. En este tutorial de dos partes, Sunil Patil presenta la arquitectura de tabla hash distribuida de Memcached y lo ayuda a comenzar a usarla para almacenar datos en caché para sus propias aplicaciones empresariales Java basadas en bases de datos.

Este tutorial le presenta el uso de Memcached para mejorar el rendimiento de las aplicaciones empresariales Java. La primera mitad comienza con una descripción general de las arquitecturas tradicionales de almacenamiento en caché de Java en comparación con la arquitectura de Memcached. También instalaremos Memcached en su máquina y le presentaré la configuración y los comandos para trabajar con Memcached a través de Telnet. En la segunda mitad, desarrollaremos un programa cliente "Hello Memcached" en Java, que usaremos para buscar bajo el capó de un cliente spymemcached. También aprenderá a usar Memcached para reducir la carga en su servidor de base de datos y usarlo para almacenar en caché el marcado de página generado dinámicamente. Finalmente, consideraremos algunas opciones avanzadas para configurar clientes spymemcached.

Más sobre el almacenamiento en caché de Java en JavaWorld

  • Consulte "Arquitecturas de equilibrio de carga del servidor, Parte 1: Equilibrio de carga a nivel de transporte" para obtener una descripción más detallada del almacenamiento en caché distribuido con Memcached.
  • Consulte también "Proyectos Java de código abierto: Java Caching System" para obtener más información sobre el almacenamiento en caché tradicional de Java.

Descripción general de las arquitecturas de almacenamiento en caché de Memcached y Java

Los marcos de almacenamiento en caché de Java como EHCache y OSCache son esencialmente HashMapobjetos en el código de su aplicación. Siempre que agregue un nuevo objeto a la caché, se almacenará en la memoria de su aplicación. Esta estrategia funciona bien para almacenar pequeñas cantidades de datos, pero no funciona para almacenar en caché más de unos pocos gigabytes (GB). Los diseñadores del servidor Memcached adoptaron un enfoque de arquitectura distribuida, que permite la escalabilidad del sistema. Como resultado, puede utilizar Memcached para almacenar en caché una gran cantidad de datos.

La arquitectura de Memcached consta de dos piezas. Primero es un servidor Memcached que se ejecuta en su propio proceso. Si desea escalar su aplicación, puede instalar y ejecutar el servidor Memcached en máquinas adicionales. Las instancias del servidor Memcached no se conocen entre sí. El cliente Memcached, la segunda pieza del sistema Memcached, no sabe de cada uno de los servidores. El cliente es responsable de seleccionar el servidor para cada entrada de caché y almacenar u obtener la entrada de caché, un proceso que analizaré en detalle más adelante en el artículo.

Si tiene algo de experiencia trabajando en aplicaciones web Java EE, es probable que haya utilizado anteriormente un marco de almacenamiento en caché de Java de código abierto, como EHCache o OSCache. También puede haber utilizado un marco de almacenamiento en caché comercial que se envió como parte de su servidor de aplicaciones, como DynaCache (que se envía con IBM WebSphere Application Server) o JBoss Cache (que se envía con JBoss AS). Antes de pasar a la parte de aprendizaje práctico de este tutorial, es importante comprender en qué se diferencia Memcached de estos marcos tradicionales de almacenamiento en caché de Java.

Usando un caché de Java tradicional

Usar un marco de almacenamiento en caché de Java tradicional es bastante fácil, independientemente de si elige una opción de código abierto o comercial. Para un marco de código abierto como EHCache u OSCache, necesitaría descargar los archivos binarios y agregar los archivos JAR necesarios a la ruta de clase de su aplicación. Es posible que también deba crear un archivo de configuración, que usaría para configurar el tamaño de la caché, la descarga del disco, etc. Para un marco de almacenamiento en caché que venía incluido con un servidor de aplicaciones, normalmente no tendría que descargar ningún JAR adicional porque se incluirían con el software.

Después de agregar soporte para el marco de almacenamiento en caché en su aplicación, puede comenzar a usarlo creando un CacheManagerobjeto y obteniendo y configurando entradas de caché en él. Bajo el capó, el marco de almacenamiento en caché crearía los CacheManagerobjetos en la misma JVM donde se estaba ejecutando su aplicación. Cada vez que agregaste una entrada de caché, ese objeto también se agregaría a algún tipo de tabla hash mantenida por el marco de almacenamiento en caché.

Si su servidor de aplicaciones se ejecuta en varios nodos, es posible que también desee compatibilidad con el almacenamiento en caché distribuido. En un sistema de caché distribuido, cuando agrega un objeto en caché en AppServer1, ese objeto también está disponible en AppServer2 y AppServer3. Los cachés tradicionales de Java utilizan la replicación para el almacenamiento en caché distribuido, lo que significa que cuando agrega una entrada de caché en AppServer1, se replica automáticamente en los otros servidores de aplicaciones de su sistema. Como resultado, la entrada estará disponible en todos sus nodos.

Usando Memcached

Para utilizar Memcached para el almacenamiento en caché, primero debe descargar e instalar el servidor Memcached para la plataforma que elija. Una vez que haya instalado el servidor Memcached, escuchará en un puerto TCP o UDP para almacenar en caché las llamadas.

A continuación, descargará un cliente Java para Memcached y agregará los JAR del cliente a su aplicación. Después de eso, puede crear un objeto de cliente Memcached y comenzar a llamar a su método para obtener y establecer entradas de caché. Cuando agrega un objeto a la caché, el cliente Memcached tomará ese objeto, lo serializará y enviará una matriz de bytes al servidor Memcached para su almacenamiento. En ese momento, el objeto almacenado en caché puede ser basura recolectada de la JVM donde se ejecuta su aplicación.

Cuando necesite ese objeto en caché, puede llamar al get()método del cliente Memcached . El cliente tomará la getsolicitud, la serializará y la enviará al servidor Memcached. El servidor Memcached utilizará la solicitud para buscar el objeto en la caché. Una vez que tenga el objeto, devolverá la matriz de bytes al cliente Memcached. El objeto del cliente Memcached tomará la matriz de bytes y la deserializará para crear el objeto y devolverlo a su aplicación.

Incluso si su aplicación se ejecuta en más de un servidor de aplicaciones, todos ellos pueden apuntar al mismo servidor Memcached y usarlo para obtener y configurar entradas de caché. Si tiene más de un servidor Memcached, los servidores no se conocerán entre sí. En su lugar, configurará su cliente Memcached para que conozca todos los servidores Memcached disponibles. Por ejemplo, si su aplicación crea un objeto Java en AppServer1 y llama al set()método de Memcached, el cliente de Memcached averiguará a qué servidor Memcached va esa entrada. Entonces comenzará a comunicarse solo con ese servidor Memcached. Del mismo modo, cuando su código en AppServer2 o AppServer3 intenta getingresar una entrada, el cliente Memcached primero descubrirá en qué servidor está almacenada esa entrada y luego se comunicará solo con ese servidor.

Lógica del cliente Memcached

En su configuración predeterminada, el cliente Memcached usa una lógica muy simple para seleccionar el servidor para una operación de obtención o configuración. Cuando haces una llamada get()o set(), el cliente toma la clave de caché y llama a su hashCode()método para obtener un número entero como 11. Luego toma ese número y lo divide por el número de servidores Memcached disponibles, digamos dos. Luego toma el valor del resto, que es 1 en este caso. La entrada de la caché irá al servidor Memcached 1. Este algoritmo simple asegura que el cliente Memcached en cada uno de sus servidores de aplicaciones siempre elija el mismo servidor para una clave de caché determinada.

Instalación de Memcached

Memcached se ejecuta en Unix, Linux, Windows y MacOSX. Puede descargar la fuente de Memcached y compilarla o puede descargar los binarios compilados por otra persona y usarlos para instalar Memcached. Aquí le explicaré el proceso de descarga de los binarios para la plataforma que elija; consulte Recursos si prefiere compilar desde la fuente.

Las siguientes instrucciones de instalación son para una máquina con Windows XP de 32 bits. Consulte Recursos para obtener instrucciones de instalación para otras plataformas, como Linux. También tenga en cuenta que el código de muestra de este artículo se desarrolló en una máquina con Windows XP de 32 bits, aunque debería funcionar en cualquier otra plataforma.

  1. El código Jellycan tiene una versión modificada de Memcached con la que es fácil y eficiente trabajar. Comience aquí descargando el archivo ZIP binario win32
  2. Expanda Memcached--win32-bin.zipen su disco duro. Tenga en cuenta que todo lo que contiene es memcached.exe. Ejecute este archivo para iniciar el servidor Memcached.
  3. Ahora ejecute memcached.exe -d installpara registrar memcached.exe como un servicio. Podrá usar la consola de Servicios para iniciar y detener el servidor Memcached.

CL arranque / parada

Intente iniciar y detener el servidor Memcached desde la línea de comandos en lugar de desde un panel de servicios. Hacer eso le dará más flexibilidad para probar diferentes opciones de línea de comandos y encontrar la mejor configuración posible para sus requisitos.

Cuando ejecuta memcached.exesin ninguna opción de línea de comandos, de forma predeterminada, el servidor Memcached se iniciará en el puerto 11211 con 64 MB de memoria. En algunos casos, es posible que desee tener un control más detallado de la configuración. Por ejemplo, digamos que el puerto 11211 es usado por algún otro proceso en su máquina y desea que el servidor Memcached use el puerto 12000; o si estaba iniciando el servidor Memcached en un entorno de QA o producción, querría darle más memoria que los 64 MB predeterminados. En estos casos, puede utilizar las opciones de la línea de comandos para personalizar el comportamiento del servidor. La ejecución del memcache.exe -helpcomando producirá una lista completa de opciones de la línea de comandos como las que se muestran en la Figura 3.

Conéctese con Memcached a través de Telnet

Una vez que se inicia el servidor Memcached, escucha en el puerto que le asignó. El cliente Memcached se conecta al servidor en el puerto TCP o UDP, envía comandos y recibe respuestas y finalmente cierra la conexión. (Consulte Recursos para obtener detalles sobre el protocolo que utiliza el cliente para comunicarse con el servidor).

Puede conectarse a su servidor Memcached de varias formas. Si está utilizando un cliente Java, como lo haremos en la segunda mitad de este tutorial, podrá acceder a una API simple para almacenar y obtener objetos de la caché. Alternativamente, puede usar un cliente Telnet para conectarse directamente al servidor. Saber cómo usar el cliente Telnet para comunicarse con el servidor Memcached es importante para depurar el cliente Java, así que comenzaremos por ahí.

Comandos Telnet

Primero, deberá usar el cliente Telnet de su elección para conectarse al servidor Memcached. En una máquina con Windows XP, simplemente puede ejecutar telnet localhost 11211asumiendo que el servidor Memcached se está ejecutando en la misma máquina y escuchando en el puerto 11211 predeterminado. Los siguientes comandos son esenciales para trabajar con Memcached a través de Telnet:

  • setagrega un nuevo elemento a la caché. La llamada es: Set . Puede escribir el valor real que debe almacenarse en la siguiente línea. Si no desea que la entrada de caché expire, ingrese 0 como valor.
  • getdevuelve el valor de la clave de caché. Utilice get para obtener el valor de keyName.
  • addagrega una nueva clave solo si aún no existe. Por ejemplo:add
  • replacereemplazará un valor solo si la clave existe. Por ejemplo:replace
  • deleteelimina la entrada de caché de la clave. Puede utilizar la llamada delete para eliminar el valor de keyName.

La captura de pantalla de la Figura 4 representa una interacción de muestra con el servidor Memcached a través de Telnet. Como se puede ver, el servidor Memcached proporciona retroalimentación a cada comando, como por ejemplo STORED, NOT_STOREDy así sucesivamente.

Conclusión de la parte 1

Hasta ahora hemos discutido brevemente las diferencias entre la arquitectura distribuida de Memcached y los sistemas de caché Java más tradicionales. También hemos configurado una implementación de Memcached en su entorno de desarrollo y ha practicado la conexión a Memcached a través de Telnet. En la siguiente parte de este tutorial usaremos el cliente Java spymemcached para configurar una solución de almacenamiento en caché distribuida para una aplicación Java de muestra. En el proceso, aprenderá mucho más sobre Memcached y cómo puede mejorar el rendimiento de sus aplicaciones Java EE.

Sunil Patil es un arquitecto de Java EE que trabaja para Avnet Technology en San Francisco, California. Es autor de Java Portlets 101 (SourceBeat, abril de 2007) y ha escrito numerosos artículos publicados por JavaWorld, IBM developerWorks y O'Reilly Media. Además de ser desarrollador y administrador de aplicaciones de WebSphere Portal Server certificado por IBM, es programador Java certificado de Sun Microsystems, desarrollador de componentes web y desarrollador de componentes comerciales. Puede ver el blog de Sunil en //www.webspherenotes.com.