Archivo de la etiqueta: scaling

La ingeniería detrás de Uber (Parte II). The Foundation

La misión de Uber es ser tan fiables como el transporte de agua corriente, en todas partes, para todo el mundo. Para hacer esto posible, creamos y trabajamos con datos complejos. Luego agrupamos muy ordenadamente la plataforma que permite a los conductores poder conseguir que las empresas y los pilotos se desplacen.

Capturas de pantalla que muestran la aplicación piloto de Uber en Nueva York, China e India para la primavera de 2016.

Capturas de pantalla que muestran la aplicación piloto de Uber en Nueva York, China e India para la primavera de 2016.

Si bien queremos que la interfaz de usuario de Uber sea simple, diseñamos sistemas complejos detrás de él para mantenerse, manejamos interacciones difíciles, y servimos grandes cantidades de tráfico de datos. (Principio KISS)

Hemos roto la arquitectura monolítica original en muchas partes a escala con el crecimiento. Con cientos de microservicios que dependen el uno del otro, dibujando un diagrama de cómo funciona Uber en este momento es tremendamente complicado, y todo cambia rápidamente. Lo que se puede cubrir en un artículo de dos partes es la pila que se utilizó para la primavera de 2016.

Desafíos de la Ingeniería de Uber: No hay usuarios gratuitos, Hyper crecimiento

Tenemos los mismos problemas de escala global como algunas de las compañías de software más exitosas, pero 1) estamos a sólo seis años de edad, por lo que no las hemos resuelto todavía, y 2) Nuestro negocio está basado en el mundo físico en tiempo real.

En abril de 2015, 300 ciudades operativas de Uber estaban dispersos por todo el mapa.

En abril de 2015, 300 ciudades operativas de Uber estaban dispersos por todo el mapa.

A diferencia de los servicios freemium, Uber tiene solo los usuarios transaccionales: pilotos, controladores y ahora los comedores y los mensajeros. La gente confía en nuestra tecnología para poder hacer dinero, ir a donde tienen que ir, así que no hay tiempo para hacer una pausa. Damos prioridad a la disponibilidad y escalabilidad.

A medida que nos ampliamos en las carreteras, nuestro servicio debe escalar. La flexibilidad de nuestra pila fomenta la competencia por lo que las mejores ideas pueden ganar. Estas ideas no son necesariamente únicas. Si existe una herramienta fuerte, la usamos hasta que nuestras necesidades exceden sus capacidades. Cuando necesitamos algo más, construimos soluciones internas. La Ingeniería de Uber ha respondido al crecimiento con gran capacidad de adaptación, la creatividad y la disciplina en el último año. Para el 2016, tenemos planes aún más grandes. En el momento en que usted lea esto, mucho habrá cambiado, pero esto es una instantánea de lo que estamos usando ahora. A través de nuestras descripciones, esperamos demostrar nuestra filosofía entorno al uso de herramientas y tecnologías.

El Stack Tecnológico de Uber

En lugar de una torre de restricciones, como la imagen de un árbol. En cuanto a las tecnologías en Uber, se ve una pila común (como un tronco de árbol) con énfasis diferentes para cada equipo o en la oficina de ingeniería (sus ramas). Es todo hecho de la misma materia, pero las herramientas y servicios florecen de manera diferente en diferentes áreas.

botswana_baobab-768x477

En pocas palabras: La plataforma

Este primer artículo se centra en la plataforma de Uber, es decir, todo lo que le da el poder más grande a la organización de la ingeniería de Uber, equipos de plataforma crean y mantienen las cosas que permiten a los ingenieros para posteriormente construir otros programas, funciones, y las aplicaciones que se utilizan.

Infraestructura y almacenamiento

Nuestro negocio se ejecuta en un modelo de nube híbrida, usando una mezcla de proveedores de la nube y múltiples centros de datos activos. Si un centro de datos falla, viajes (y todos los servicios asociados con viajes) conmutación por error a otro. Asignamos ciudades para el centro de datos más cercano geográficamente, pero cada ciudad se copian en un centro de datos diferente en otra ubicación. Esto significa que todos nuestros centros de datos son los viajes en todos los tiempos de funcionamiento; no tenemos noción de un centro de datos como “copia de seguridad”. Para la provisión de esta infraestructura, se utiliza una mezcla de herramientas internas y Terraform.

Las nubes híbridas combinan los modelos de nubes públicas y privadas. Un usuario es propietario de unas partes y comparte otras, aunque de una manera controlada. Las nubes híbridas ofrecen la promesa del escalado, aprovisionada externamente, a demanda, pero añaden la complejidad de determinar cómo distribuir las aplicaciones a través de estos ambientes diferentes. Las empresas pueden sentir cierta atracción por la promesa de una nube híbrida, pero esta opción, al menos inicialmente, estará probablemente reservada a aplicaciones simples sin condicionantes, que no requieran de ninguna sincronización o necesiten bases de datos complejas. Se unen mediante la tecnología, pues permiten enviar datos o aplicaciones entre ellas. Un ejemplo son los sistemas de correo electrónico empresarial.  https://es.wikipedia.org/wiki/Computaci%C3%B3n_en_la_nube

Nuestras necesidades de almacenamiento han cambiado con el crecimiento. Un ejemplo sencillo de Postgres nos llevó a través de nuestra infancia, pero a medida que fue creciendo tan rápidamente, fue necesario aumentar el tiempo de almacenamiento en disco y la disminución de respuesta del sistema disponibles.

Al final del verano de 2014, Proyecto Mezzanine rediseñado el sistema para que coincida con la arquitectura de alto nivel.

Al final del verano de 2014, Proyecto Mezzanine rediseñando el sistema para que coincida con la arquitectura de alto nivel.

Actualmente usamos un modelo sin esquema (construido in-house en la parte superior del stack de MySQL), Riak, y Cassandra. Sin esquema es para el almacenamiento de datos a largo plazo; Riak y Cassandra se reúnen como plataforma de alta disponibilidad, y las demandas de baja latencia. Con el tiempo, las instancias sin esquema reemplazaron instancias individuales de MySQL y Postgres, y Cassandra reemplazó a Riak debido a la velocidad y el rendimiento. Para el almacenamiento y análisis de datos complejos distribuidos, utilizamos un almacén Hadoop. Más allá de estas bases de datos, nuestros ingenieros de Seattle se centran en la construcción de una nueva plataforma de datos en tiempo real.

Utilizamos Redis tanto para el almacenamiento en caché y la puesta en cola. Twemproxy ofrece escalabilidad de la capa de almacenamiento en caché sin sacrificar la tasa de aciertos de caché a través de su algoritmo de hash coherente.

Logging

Nuestros servicios interactúan entre sí y con los dispositivos móviles, y esas interacciones son valiosas para usos internos como la depuración, así como los casos de negocios como precios dinámicos. Para el registro, utilizamos varios clústeres Kafka, y los datos se archivan en Hadoop y/o en un servicio web de almacenamiento de archivos antes de que caduque Kafka. Estos datos también se ingiere en tiempo real por los diversos servicios e indexados en una pila ELK para la búsqueda y visualización (ELK significa Elasticsearch, Logstash, y Kibana).

App Provisioning

Utilizamos contenedores Docker sobre Mesos para hacer funcionar nuestros microservicios con configuraciones consistentes de manera evolutiva, con la ayuda de Aurora para los servicios de larga duración y los trabajos de cron. Uno de nuestros equipos de infraestructura, la plataforma de aplicaciones, produjo una biblioteca de plantillas que se basa en los servicios de imágenes fáciles de enviar y acoplables.

Routing and Service Discovery

Nuestra arquitectura orientada al servicio (SOA) hace que el descubrimiento de servicios de enrutamiento sea crucial para el éxito de Uber. Los servicios deben ser capaces de comunicarse entre sí en nuestra compleja red. Hemos utilizado una combinación de HAProxy y Hyperbahn para resolver este problema. Hyperbahn es parte de una colección de software de código abierto desarrollado en Uber: Ringpop, TChannel, y Hyperbahn todos comparten una misión común para agregar la automatización, la inteligencia, y el rendimiento de una red de servicios.

Los servicios legados utilizan instancias locales HAProxy para encaminar JSON sobre peticiones HTTP a otros servicios, con el servidor front-end web Nginx a los servidores en el extremo posterior. De esta forma bien establecida de la transferencia de datos hace que la solución de problemas sea fácil, que era crucial a lo largo de varias migraciones a sistemas recientemente desarrollados en el último año.

Sin embargo, estamos dando prioridad a la fiabilidad a largo plazo sobre la capacidad de depuración (debuggability). Usando protocolos alternativos para HTTP (como spdy, HTTP/2, y TChannel) junto con los lenguajes de definición de interfaz como Thrift y Protobuf que ayudarán a evolucionar nuestro sistema en términos de velocidad y fiabilidad. Ringpop, una capa de hash coherente, trae la cooperación y la auto-sanación (self-healing) a nivel de aplicación. Hyperbahn permite que los servicios puedan encontrarse y comunicarse con los demás de forma sencilla y fiable, así como los servicios se programan de forma dinámica con Mesos.

En lugar del arcaico pooling para ver si algo ha cambiado, nos estamos moviendo a un patrón de pub-sub (publicación de actualizaciones a los suscriptores). HTTP/2 y spdy permiten más fácilmente este modelo de inserción. Varias características basadas en este “pooling” dentro de la aplicación de Uber verán una tremenda aceleración de mover para empujar usando pub-sub.

Development and Deploy

Phabricator provee una gran cantidad de poder para poder manejar nuestra gran cantidad de operaciones internas, a partir de la revisión de código hasta el proceso de la documentación automatizado. Buscamos a través de nuestro código en OpenGrok. Para proyectos de código abierto de Uber, desarrollamos utilizando GitHub para proyectos de código abierto y para el seguimiento de problemas y revisiones de código.

Los ingenieros de Uber  se esfuerzan por hacer que el desarrollo pueda simular el ambiente de producción lo más cerca posible, por lo que desarrollan principalmente en máquinas virtuales que se ejecutan en un proveedor de la nube o en el portátil de un desarrollador. Construimos nuestro propio sistema de despliegue interno para gestionar las construcciones. Jenkins hace la integración continua. Se combinaron Packer, Vagrant, Boto, y Unison para crear herramientas para la construcción, gestión y desarrollo de las máquinas virtuales. Utilizamos Clusto para la gestión de inventarios en el desarrollo. Puppet gestiona la configuración del sistema.

Trabajamos constantemente para construir y mantener canales de comunicación estables, no sólo para nuestros servicios, sino también para nuestros ingenieros. Para el descubrimiento de información, construimos uBlame (un guiño a git-blame) para realizar un seguimiento de qué equipo es propietario de un determinado servicio, y Whober para buscar nombres, caras, información de contacto, y la estructura organizativa. Utilizamos un sitio de documentación interna que auto construye documentos contactándose con repositorios utilizando Sphinx. Un servicio empresarial de alerta a nuestros ingenieros de guardia para mantener los sistemas en funcionamiento. La mayoría de los desarrolladores ejecutar OS X en sus computadoras portátiles, y Linux la mayoría de nuestros casos de producción se ejecutan con Debian Jessie.

Languages

En los niveles más bajos, los ingenieros de Uber escriben principalmente en Python, Node.js: Go, y Java. Comenzamos con dos lenguas principales: Node.js para el equipo del mercado, y Python para todos los demás. Estas primeras lenguas todavía alimentan la mayoría de los servicios que se ejecutan en Uber hoy.

Adoptamos Go y Java por razones de alto rendimiento. Proporcionamos soporte de primera clase para los lenguajes. Java se aprovecha del ecosistema de código abierto y se integra con las tecnologías externas, como Hadoop y otras herramientas de análisis. Go nos da eficiencia, simplicidad y velocidad de ejecución.

Nosotros sustituimos el viejo código Python mayor dado que el objetivo es romper el código base original en microservicios. Un modelo de programación asíncrona nos da un mejor rendimiento. Utilizamos Tornado con Python, pero el soporte nativo de Go, para la concurrencia es ideal para la mayoría de los nuevos servicios de rendimiento crítico.

Escribimos herramientas en C y C ++ cuando es necesario (como por alta eficiencia, código de alta velocidad a nivel del sistema). Utilizamos software que está escrito en los lenguajes de HAProxy, por ejemplo-, pero en su mayor parte, no  trabajamos en ellos.

Y, por supuesto, los que trabajan en la parte superior de la pila de escritura en las lenguajes más allá de Java, Go, Python, y Node.

Testing

Para asegurarnos de que nuestros servicios pueden manejar las demandas de nuestro entorno de producción, hemos desarrollado dos herramientas internas: Tormenta de granizo y uDestroy. Tormenta de granizo impulsa las pruebas de integración y simula la carga máxima fuera de las horas pico, mientras que uDestroy rompe intencionadamente cosas por lo que podemos mejorar en el manejo de fallos inesperados.

Nuestros empleados utilizan una versión beta de la aplicación para poner a prueba continuamente nuevos desarrollos antes de que lleguen a los usuarios. Hicimos un reportero de comentarios sobre la aplicación de atrapar cualquier error antes de que llegue a los usuarios. Cada vez que se toma una captura de pantalla de las aplicaciones Uber, esta característica nos lleva a presentar una tarea de corrección de errores en Phabricator.

Fin…

No pude traducir el artículo completo por cuestiones de tiempo, pero eso si, traté de centrarme en las cosas importantes (una parte en realidad) y en el stack tecnológico, que creo podrá darnos algunas buenas pautas para que aprendamos como escalar a partir de una arquitectura monolítica.  Estos temas son relevantes para quienes desean formarse como arquitectos de software.  Conocer de tecnología es de hecho una habilidad dura que debiese correr por las venas de quienes deseen formarse en este interesante (y hermoso) mundo.  En la siguiente parte espero poder hablar más acerca de los asuntos relacionados con las app móviles y como interactuar en tiempo real cuando nos enfrentamos al problema geográfico, como distribuir la arquitectura lógica del software en capas que ayuden en parte a ir resolviendo estos problemas.  Espero les sea de utilidad…  Nos vemos!

Fuente: https://eng.uber.com/tech-stack-part-one/

Anuncios

1 comentario

Archivado bajo Arquitectura de Sistemas, Arquitectura de Software, Ingeniería de Software