Artículo anterior: La ingeniería detrás de Uber (Parte I)
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 choferes se desplacen.
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.
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 la 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.
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 nuestros inicios, 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.
Actualmente usamos un modelo NoSQL (construido in-house en la parte superior del stack de MySQL), Riak, y Cassandra. NoSQL 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 NoSQL 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 infieren 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 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 ejecutan 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 lenguajes principales: Node.js para el equipo del mercado, y Python para todos los demás. Estos primeros lenguajes 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/