eBayHay pocas aplicaciones web como eBay que ejemplifiquen tan bien las necesidades de una empresa para escalar y satisfacer la demanda. eBay tiene 88.3 millones de usuarios activos en todo el mundo, más de 2 mil millones de páginas mostradas por día, y 48 mil millones de ejecuciones SQL por día. Randy Shoup, arquitecto de la web de eBay y el arquitecto principal de la infraestructura de búsqueda del sitio, nos cuenta cómo hacen para satisfacer esta demanda.

Objetivos del diseño

Las metas arquitectónicas de eBay son:

  • Escalabilidad. El objetivo es que la utilización de recursos se incremente en forma lineal junto a la carga.
  • Alta disponibilidad. El sistema es resistente a los fallos y permite una degradación suave y rápida recuperación ante fallas.
  • Baja latencia. Se minimizan los tiempos de espera tanto para la experiencia del usuario, para la búsqueda de datos y para la ejecución.
  • Gestionable. El sistema está diseñado para ser simple y mantenible, con herramientas de diagnóstico listas para usar.
  • Costo minimo. Las decisiones de arquitectura buscaron el diseño con la mejor relación costo/efectividad, tanto al momento de desarrollo como de despliegue.

Mejores prácticas

Shoup describe la arquitectura que cumple con estas metas, resumiéndo el diseño en términos de un conjunto de mejores prácticas:

  • Particionar todo
  • Todo asíncrono
  • Automatizar todo
  • Recordar que todo falla
  • Adaptarse a la inconsistencia

Particionar todo

No se puede escarlar un sistema que no puede separarse en módulos. Al particionar pensando en escalar, eBay descompone los problemas en piezas manejables, que tienen enorme carga y cantidad de usuarios presentes. Las piezas más pequeñas pueden escalar independientemente de otras. En eBay no existe algo como "La base de datos" o "El servidor de aplicaciones". Cada parte del problema, a través de cada capa, se particiona o balancea su carga de alguna forma.

Una estrategia de particionado es usar la segmentación funcional. Este enfoque segmenta al procesamiento en pooles, servicios y etapas - por ejemplo, ventas, búsquedas, ofertas, compras y feedback. Otra estrategia es segmentar los datos por entidad y patrón de uso - por ejemplo, usuario, elemento, transacción, producto y cuenta.

Una consecuencia de esta segmentación es que no existe una base de datos única sobre la que corre todo el sitio de eBay. En cambio, muchas bases de datos lógicas reflejan las distintas partes funcionales del sitio. Por ejemplo, bases de datos separadas almacenan la información de ventas, la información de elementos, la información de usuarios, las transacciones recientes, y así. Como resultado, eBay mantiene más de 1000 instancias de bases de datos lógicas distintas, repartidas sobre más de 400 servidores.

Un sistema que escala en piezas independientes es más facil de depurar porque las fallas estás más aisladas. Estas piezas desacopladas también son más fáciles de administrar y pueden dimensionarse para maximizar el ratio costo/rendimiento.

Descomponer el problema en piezas más pequeñas no sólo involucra una segmentación vertical sino también horizontal, especialmente en la forma de balanceo de carga. En el balanceo de carga, todos los servidores de un pool - ventas, búsqueda, ofertas, y así- tienen los mismos derechos. A su vez, los datos se separan (data sharding) en distintas rutas de acceso - usuario, elemento, transacción y demás.

Como resultado de esta segmentación horizontal, las sesiones no llevan información de estado. Una sesión de usuario fluye a través de múltiples pools - ventas, búsqueda, ofertas - pero no hay ningún estado de sesión u objeto de negocio que tenga un caché de la capa de aplicación del sistema. La información de estado no se almacena en un HttpSession o en un Enterprise JavaBean. En cambio, la sesión se mantiene en una cookie, en la URL o en la base de datos.

Todo asíncrono

Cuando se segmenta un sistema, la comunicación asíncrona tiene muchas ventajas:

  • Los segmentos individuales pueden escalar independientemente. Cuando cualquier segmento comienza a ser un cuello de botella, puede escalarse.
  • Se mejora la disponibilidad. Porque los segmentos no comparten información de estado, es más facil hacer reintentos.
  • Se puede manejar la latencia porque se puede negociar la latencia de ejecución por latencia de respuesta.
  • Se pueden minimizar los costos porque se pueden distribuir la carga pico a través del tiempo.

La asincronía se usa lo más posible en eBay. El objetivo es minimizar la latencia en la experiencia del usuario. Las ejecuciones que no cumplen esta meta se posponen cuando es necesario.

eBay utiliza dos estrategias para implementar asincronismo: colas de eventos y mensajes multicasting.

Asincronismo: Colas de Eventos

Cuando se implementa una cola de eventos, una aplicación principal escribe datos en una base de datos transaccional y encola el evento usando invocaciones insert/update como ITEM.NUEVO, ITEM.OFERTAR, ITEM.VENDER. Los consumidores se suscriben al evento, y los datos se entregan sin un orden garantizado, con una entrega del modo al-menos-una-vez en vez de exactamente-una-vez, y con idempotencia para garantizar la disponibilidad.

Asincronismo: Mensajes Multicasting

Shoup puede describir perfectamente la escalabilidad en la implementación de búsqueda de eBay, porque es el arquitecto en jefe de esa área. La enorme cantidad de datos que maneja el sitio es un desafio para lograr disponibilidad y rendimiento. La arquitectura de búsqueda utiliza modularidad y mensajes multicasting para lograr estos objetivos.

El índice de búsquedas se divide en porciones y se almacena como una estructura en grilla compuesta de columnas y filas. Cada porción del índice se almacena en una columna de computadoras. Las filas de cada columna representan copias redundantes de esa porción.

La implementación tiene que escalar cuando el índice de búsqueda se vuelve más grande o se incrementa la carga. Cuando el índice de búsqueda se vuelve más grande, se agregan más columnas. Cuando se incrementan la carga, se agregan más filas. Entonces la grilla escala tanto verticalmente como horizontalmente.

Arquitectura de eBay

Los mensajes multicasting entran en juego con un Publicador de Búsquedas (Search Feeder) y un Motor de Búsqueda (search engine). El Publicador de Búsquedas publica actualización de elementos, leyendo de una base de datos principal, y luego publica las actualizaciones secuenciadas a la grilla con multicasting.

Los Motores de Búsqueda escuchan los mensajes y actualizan un índice en memoria en tiempo real. Para garantizar la confiabilidad, los motores de búsqueda piden recuperar datos cuando ven que se perdieron un mensaje en la secuencia. Al implementar el recupero de mensajes a nivel de aplicación en vez de a nivel de transporte permitió mejorar la escalabilidad.

Automatizar todo

La escalabilidad involucra más que la habilidad de agregar de manera facil nodos y funcionalidad al sitio web. Estas capacidades adicionales no son útiles si incrementan la complejidad de la gestión necesaria para mantener la nueva configuración. Para reducir la carga al personal, eBay automatiza lo más posibles las tareas administrativas. Necesitan crear bucles de feedback que aprenden con el tiempo para diseñar sistemas que se adapten al entorno. Además, la práctica de capturar errores en estos bucles y escribir archivos de log ofrece beneficios adicionales al momento de depurar las aplicaciones.

Otra ventaja de un sistema automatizado y adaptativo es que puede hacer más que un sistema configurado manualmente. Puede considerar más factores y tomar decisiones con más rapidez. Los sistemas resultantes tienen menor latencia y, como tienen menos intervención humana, cuesta menos.

Automatización: Configuración Adaptativa

Un patrón de diseños automatizados es la configuración adaptativa. Con la configuración adaptativa, los parámetros de rendimiento (frecuencia de comprobaciones, cantidad de hilos, etc.) se determinan no en archivos de configuración estáticos, sino por condiciones de carga.

Para un evento de un consumidor determinado, eBay define un Acuerdo de Nivel de Servicio (SLA). Por ejemplo, un SLA puede requerir que el 99% de los eventos se procesen en 15 segundos. Cada consumidor del evento puede ajustarse automáticamente para cumplir el SLA a medida que cambia la carga, el tiempo y de procesamiento y la cantidad de eventos.

Automatización: máquinas que aprenden

Otro patrón de diseño es el de Máquinas que Aprenden. Por ejemplo, la experiencia de búsqueda para los usuarios se adapta automáticamente determinando los elementos de venta más apropiados, y ensambando una página óptima para cada usuario particular y su contexto. Los bucles de feedback le permiten al sistema aprender y mejorar con el tiempo. El sistema recolecta el comportamiento del usuario, agrega y analiza esta información fuera de línea. Luego despliega esta metadata actualizada que determina la experiencia personalizada del usuario.

Recordar que todo falla

Para maximinar la disponibilidad, eBay diseña a todos los sistemas para ser tolerantes a fallas. El diseño sigue estando gobernado por la presunción que cada operación fallará en algún punto, y que todos ningún recurso estará disponible.

Cuando ocurre un error de estas características, el objetivo del diseño es detectarlo rápidamente, recuperarse apropiadamente, y continuar la operación lo más posible mientras tanto.

Fallas: detección, recuperación y degradación suave

Para detectar fallas, los servidores de aplicaciones registran toda la actividad de las aplicaciones, bases de datos, e invocaciones a servicios en el bus de mensajes. El sistema genera más de 2TB de mensajes de log por día. Hay listeners automatizados para detectar fallas y realizar notificaciones.

La recuperación ante fallas se ve ayudada por las capacidades de rollback. No se hace ningún cambio al sitio que no pueden deshacerse, y cada característica tiene un estado de apagado/prendido que puede cambiarse, tanto sea por motivos operacionales o de negocio. Las características pueden desplegarse con un estado "apagado" de manera predeterminada, de manera de poder activarlo o desactivarlo si resulta necesario.

Otro patrón de diseño que implementa la disponibilidad es la Degradación Suave. Una aplicación "marca como inusable" a un recurso si no está disponible o estresado. Si esta función no disponible no es crítica, se quita o se ignora. Si es crítica, la aplicación reintenta, a menudo con algún recurso alternativo. Si el reintento también falla, se difiere el procesamiento a un evento asincrono. Cuando el recurso se recupera, se los "marca como usables" y se vuelven a poner online de forma controlada.

Adaptarse a la inconsistencia

Por último, los arquitectos de eBay aceptan y se adaptan a las inconsistencias.

Como cualquier sitio de Internet grande, eBay se encontró limitado por el teorema de CAP (propuesto por primera vez por Eric Brewer en julio de 2000). Resumidamente, el teorema explica que todo sistema con datos compartidos puede tener como máximo dos de las siguientes propiedades:

  • Consistencia: todos los clientes ven los mismos datos, incluso ante la presencia de actualizaciones.
  • Disponibilidad: todos los clientes obtienen una respuesta, incluso ante la presencia de fallas.
  • Toleracia a particiones: las propiedades del sistema se mantienen incluso cuando la red está particionada, como ser durante un fallo de hardware de red.

En los sistemas distribuidos es fundamental hacer las conseciones necesarias sobre estas tres propiedades.

Los diseñadores de eBay investigaron el teorema, y eligieron disponibilidad y tolerancia a particiones, y a la vez usaron políticas para forzar la consistencia que garantizaba una consistencia eventual en algún marco de tiempo.

En genearl, eBay prefiere disponibilidad y tolerancia a particiones por sobre una consistencia inmediata. El motivo de esto es que la mayoría de los sistemas reales - incluso los sistemas financieros - no necesitan una consistencia inmediata.

Los requerimientos de consistencia se ven como en un espectro: en una punta del espectro están los requerimientos de consistencia inmediata, como ser los datos de una oferta y compra. En la otra punta están los requerimientos con muy baja necesidad de consistencia, como ser las preferencias de un usuario. En el medio están la "consistencia eventual", como ser los datos que muestra el motor de búsquedas, facturación y otros.

Para incrementar la consistencia inmediata, eBay evita distribuir transacciones como las transacciones de clientes JDBC. La consistencia se maximiza con máquinas de estado y un ordenamiento cuidadoso de las operaciones en la base de datos. La consistencia eventual se logra a través de eventos asincrónicos o procesos de reconcialiación batch.

Traducido de Technical Session: best practices for large-scale web sites -- Lessons from eBay.

Inspiración.

"Si tú tienes una manzana y yo tengo una manzana e intercambiamos las manzanas, entonces tanto tú como yo seguiremos teniendo una manzana cada uno. Pero si tú tienes una idea y yo tengo una idea, e intercambiamos las ideas, entonces ambos tendremos dos ideas"

Bernard Shaw