La misión de Uber es ser un transporte tan confiable como el agua corriente, en todas partes y para todos. Para hacerlo posible, se trabajan con datos complejos. Luego se agrupan cuidadosamente como una plataforma que permite a los conductores hacer negocios y a los pasajeros moverse.
Si bien se quiere que la interfaz de usuario de Uber sea simple, se diseñan sistemas complejos detrás de ella para mantenerse en funcionamiento, manejar interacciones difíciles y atender cantidades masivas de tráfico. Se ha dividido la arquitectura monolítica original en muchas partes para escalar con el crecimiento. Con cientos de microservicios que dependen unos de otros, dibujar un diagrama de cómo funciona Uber en este punto es tremendamente complicado y todo cambia rápidamente.
Los desafíos de Uber Engineering
Se tienen los mismos problemas a escala global que algunas de las empresas de software más exitosas, pero 1) solo se tienen seis años, por lo que aún no se han resuelto y 2) el negocio se basa en el mundo físico en realidad hora.
A diferencia de los servicios freemium, Uber solo tiene usuarios transaccionales: pasajeros, conductores y ahora comensales y mensajeros. Las personas confían en la tecnología, para ganar dinero, para ir a donde necesitan ir , por lo que no hay un momento seguro para hacer una pausa.
Priorizamos la disponibilidad y la escalabilidad.
A medida de que se expande en las carreteras, los servicio debe escalar. La flexibilidad de la pila fomenta la competencia para que las mejores ideas puedan ganar. Estas ideas no son necesariamente únicas. Si existe una herramienta sólida, se usa hasta que las necesidades superan sus capacidades. Cuando se necesita algo más, se crean soluciones internas . Uber Engineering ha respondido al crecimiento con una tremenda adaptabilidad, creatividad y disciplina en el último año.
Pila de tecnología de Uber
En lugar de una torre de restricciones, imagina un árbol. Si observa las tecnologías en Uber, verá una pila común (como el tronco de un árbol) con diferentes énfasis para cada equipo u oficina de ingeniería (sus sucursales). Todo está hecho del mismo material, pero las herramientas y los servicios florecen de manera diferente en varias áreas.
Infraestructura y almacenamiento
El negocio se ejecuta en un modelo de nube híbrida, utilizando una combinación de proveedores de nube y múltiples centros de datos activos. Si un centro de datos falla, los viajes (y todos los servicios asociados con los viajes) fallan a otro. Se asignan ciudades al centro de datos geográficamente más cercano, pero cada ciudad está respaldada en un centro de datos diferente en otra ubicación. Esto significa que todos los centros de datos están realizando viajes en todo momento; no se tiene la noción de un centro de datos de «respaldo». Para aprovisionar esta infraestructura, se utiliza una combinación de herramientas internas y Terraform .
Las necesidades de almacenamiento han cambiado con el crecimiento. Una sola instancia de Postgres ayudó a superar la infancia , pero a medida que se crece tan rápido, se necesita aumentar el almacenamiento en disco disponible y disminuir los tiempos de respuesta del sistema.
Actualmente se usa Schemaless (construido internamente sobre MySQL) , Riak y Cassandra. Schemaless es para el almacenamiento de datos a largo plazo; Riak y Cassandra cumplen con las demandas de alta disponibilidad y baja latencia. Con el tiempo, las instancias sin esquema reemplazan las instancias individuales de MySQL y Postgres , y Cassandra reemplaza a Riak en cuanto a velocidad y rendimiento. Para el almacenamiento distribuido y el análisis de datos complejos, se utiliza un almacén de Hadoop . Más allá de estas bases de datos, los ingenieros de Seattle se centran en crear una nueva plataforma de datos en tiempo real.
Se usa Redis tanto para el almacenamiento en caché como para la cola. Twem proxy proporciona escalabilidad de la capa de almacenamiento en caché sin sacrificar la tasa de aciertos de caché a través de su algoritmo de hash consistente. Los trabajadores de apio procesan operaciones de flujo de trabajo asíncronas utilizando esas instancias de Redis.
Inicio sesión
Los servicios interactúan entre sí y con los dispositivos móviles, y esas interacciones son valiosas para usos internos como depuración, así como casos comerciales como precios dinámicos. Para el registro, se utilizan varios clústeres de Kafka y los datos se archivan en Hadoop y/o en un servicio web de almacenamiento de archivos antes de que caduquen en Kafka. Estós datos también se ingiere en tiempo real por diversos servicios e indexados en una pila ELK para la busqueda y visualizacion (ELK SIGNIFICA Elasticsearch , Logstash y Kibana ).
Aprovisionamiento de aplicaciones
Se usan contenedores Docker en Mesos para ejecutar los microservicios con configuraciones consistentes de manera escalable, con la ayuda de Aurora para servicios de larga duración y trabajos cron. Uno de los equipos de infraestructura, Application Platform, produjo una biblioteca de plantillas que integra servicios en imágenes de Docker que se pueden enviar.
Enrutamiento y descubrimiento de servicios
La arquitectura orientada a servicios (SOA) hace que el descubrimiento y el enrutamiento de servicios sean cruciales para el éxito de Uber. Los servicios deben poder comunicarse entre sí en nuestra compleja red. Se han utilizado una combinación de HAProxy e Hyperbahn para resolver este problema. Hyperbahn es parte de una colección desoftware de código abierto desarrollado en Uber: Ringpop , TChannel e Hyperbahn comparten la misión común de agregar automatización, inteligencia y rendimiento a una red de servicios.
Los servicios heredados utilizan instancias locales de HAProxy para enrutar JSON a través de solicitudes HTTP a otros servicios, con el servidor web front-end NGINX haciendo proxy a los servidores en el back-end. Esta forma bien establecida de transferir datos facilita la resolución de problemas, lo cual fue crucial durante varias migraciones a sistemas recientemente desarrollados en el último año.
Sin embargo, se esta priorizando la confiabilidad a largo plazo sobre la depuración. Los protocolos alternativos a HTTP (como SPDY, HTTP / 2 y TChannel) junto con lenguajes de definición de interfaz como Thrift y Protobuf ayudarán a evolucionar los sistema en términos de velocidad y confiabilidad. Ringpop, una capa hash consistente, aporta cooperación y autocuración al nivel de la aplicación. Hyperbahn permite que los servicios encuentren y se comuniquen con otros de manera simple y confiable, incluso cuando los servicios se programan dinámicamente con Mesos .
En lugar de sondear arcaicamente para ver si algo ha cambiado, se mueven a un patrón pub-sub. HTTP / 2 y SPDY habilitan más fácilmente este modelo de inserción. Varias funciones basadas en encuestas dentro de la aplicación Uber verán una tremenda aceleración al moverse para empujar.
Desarrollo e implementación
Phabricator impulsa muchas operaciones internas, desde la revisión del código hasta la documentación y la automatización de procesos. Se busca a través del código en OpenGrok . Para los proyectos de código abierto de Uber, se desarrolla en abierto usando GitHub para el seguimiento de problemas y revisiones de código.
Uber Engineering se esfuerza por hacer que el desarrollo simule la producción lo más fielmente posible, por lo que se desarrolla principalmente en máquinas virtuales que se ejecutan en un proveedor de nube o en la computadora portátil de un desarrollador. Se crea un sistema propio de implementación interno para administrar las compilaciones. Jenkins hace una integración continua. Combinamos Packer , Vagrant , Boto y Unison para crear herramientas para construir, administrar y desarrollar en máquinas virtuales. Usamos Clusto para la gestión de inventarios en desarrollo. Puppet gestiona la configuración del sistema.
Se trabaja constantemente para construir y mantener canales de comunicación estables, no solo para los servicios sino también para los ingenieros. Para el descubrimiento de información, se crea uBlame para realizar un seguimiento de qué equipo posee un servicio en particular y Whober para buscar nombres, rostros, información de contacto y estructura organizativa. Se usa un sitio de documentación interno que crea automáticamente documentos a partir de repositorios usando Sphinx . Un servicio de alerta empresarial alerta a los ingenieros de guardia para que mantengan los sistemas en funcionamiento. La mayoría de los desarrolladores ejecutan OSX en sus computadoras portátiles y la mayoría de las instancias de producción ejecutan Linux con Debian Jessie .
Lenguajes
En los niveles inferiores, los ingenieros de Uber escriben principalmente en Python, Node.js, Go y Java. Se comienza con dos lenguajes principales: Node.js para el equipo de Marketplace y Python para todos los demás. Estos primeros lenguajess aún impulsan la mayoría de los servicios que se ejecutan en Uber en la actualidad.
Se adopta Go y Java por razones de alto rendimiento. Se brinda soporte de primera clase para estos lenguajes. Java aprovecha el ecosistema de código abierto y se integra con tecnologías externas, como Hadoop y otras herramientas de análisis. Go brinda eficiencia, simplicidad y velocidad de ejecución.
Se extrae y reemplaza el código Python anterior a medida que se divide la base del código original en microservicios . Un modelo de programación asincrónico brinda un mejor rendimiento. Se usa Tornado con Python, pero el soporte nativo de Go para la concurrencia es ideal para la mayoría de los nuevos servicios críticos para el rendimiento.
Se escriben herramientas en C y C ++ cuando es necesario (como para código de alta eficiencia y alta velocidad a nivel del sistema). Se usa software que está escrito en esos lenguajes, HAProxy, por ejemplo, pero en su mayor parte, no trabajamos en ellos.
Y, por supuesto, aquellos que trabajan en la parte superior de la pila escriben en lenguajes más allá de Java, Go, Python y Node.
Pruebas
Para asegurar de que los servicios puedan manejar las demandas de el entorno de producción, se han desarrollado dos herramientas internas: Hailstorm y uDestroy. Hailstorm impulsa las pruebas de integración y simula la carga máxima durante las horas no pico, mientras que uDestroy rompe intencionalmente las cosas para que se pueda mejorar en el manejo de fallas inesperadas.
Los empleados utilizan una versión beta de la aplicación para probar continuamente nuevos desarrollos antes de que lleguen a los usuarios. Se crea un reportero de comentarios de la aplicación para detectar cualquier error antes de implementarlo para los usuarios. Siempre que se toma una captura de pantalla en las aplicaciones de Uber, esta función pide que presentemos una tarea de corrección de errores en Phabricator.
Usar datos de forma creativa
Storm y Spark procesan flujos de datos en métricas comerciales útiles. El equipo de visualización de datos crea marcos y aplicaciones reutilizables para consumir datos visuales.
Las visualizaciones de tablas e intervalos de confianza añaden funcionalidad a la plataforma de pruebas A / B, Morpheus.
Los equipos de mapeo y experimentación confían en la visualización de datos para convertir los datos en información clara y sensible. Los equipos de operaciones de la ciudad pueden ver a los conductores en su ciudad fluyendo en tiempo real como automóviles en un mapa en el lugar de obtener información de consultas tediosas SQL.
Se usa JavaScript ( ES5 y ES6 ) y React para crear productos de datos como herramientas principales. También se utiliza todos los estándares web para gráficos en los componentes de visualización: SVG, Canvas 2D y WebGL . Muchas de las bibliotecas que se desarrollan son de código abierto, como react-map-gl , de las que se dependen para mapear visualizaciones:
Las visualizaciones demuestran la capacidad de react-map-gl , un contenedor para MapboxGL-js desarrollado por el equipo de visualización de datos de Uber.