Está en la página 1de 18

http://eng.uber.

com/uber-big-data-platform/

La plataforma de Big Data de Uber: más de 100 petabytes con latencia de


minutos

Uber se compromete a ofrecer un transporte más seguro y confiable en nuestros


mercados globales. Para lograr esto, Uber se basa en gran medida en la toma
de decisiones basadas en datos en todos los niveles, desde la predicción de la
demanda de pasajeros durante eventos de alto tráfico hasta la identificación y
solución de cuellos de botella en nuestro proceso de registro de socios
conductores. Con el tiempo, la necesidad de más información ha dado como
resultado más de 100 petabytes de datos analíticos que deben limpiarse,
almacenarse y servirse con una latencia mínima a través de nuestra plataforma
Big Data basada en Hadoop. Desde 2014, hemos trabajado para desarrollar una
solución de Big Data que garantice la confiabilidad, escalabilidad y facilidad de
uso de los datos, y ahora nos estamos enfocando en aumentar la velocidad y la
eficiencia de nuestra plataforma.
En este artículo, nos sumergimos en el viaje de la plataforma Hadoop de Uber y
discutimos lo que estamos construyendo a continuación para expandir este
ecosistema rico y complejo.

Generación 1: El comienzo de Big Data en Uber

Antes de 2014, nuestra cantidad limitada de datos podría caber en algunas bases
de datos tradicionales de procesamiento de transacciones en línea (OLTP) (en
nuestro caso, MySQL y PostgreSQL). Para aprovechar estos datos, nuestros
ingenieros tuvieron que acceder a cada base de datos o tabla individualmente, y
se dejó a los usuarios escribir su propio código si necesitaban combinar datos
de diferentes bases de datos. En ese momento, no teníamos acceso global ni
una vista global de todos nuestros datos almacenados. De hecho, nuestros datos
estaban dispersos en diferentes bases de datos OLTP, el tamaño total de los
datos era del orden de unos pocos terabytes, y la latencia para acceder a estos
datos fue muy rápida (a menudo, por minuto). La Figura 1, a continuación,
proporciona una visión general de nuestra arquitectura de datos antes de 2014:
Figura 1: Antes de 2014, la cantidad total de datos almacenados en Uber era lo
suficientemente pequeña como para caber en algunas bases de datos OLTP tradicionales.
No hubo una vista global de los datos, y el acceso a los datos fue rápido ya que cada base
de datos fue consultada directamente.

Con el negocio de Uber creciendo exponencialmente (tanto en términos de la


cantidad de ciudades / países en los que operamos como de la cantidad de
pasajeros / conductores que utilizan el servicio en cada ciudad), la cantidad de
datos entrantes también aumentó y la necesidad de acceder y analizar todos los
datos en un solo lugar nos obligaron a construir la primera generación de nuestro
almacén de datos analíticos. Para que Uber sea lo más basado en datos posible,
necesitamos asegurarnos de que los datos analíticos sean accesibles para los
analistas, todo en un solo lugar. Para lograr este objetivo, primero categorizamos
a nuestros usuarios de datos en tres categorías principales:

1. Equipos de operaciones de la ciudad (miles de usuarios): estos equipos


en tierra administran y amplían la red de transporte de Uber en cada mercado.
Con nuestro negocio expandiéndose a nuevas ciudades, hay miles de equipos
de operaciones de la ciudad que acceden a estos datos de manera regular para
responder a problemas específicos de conductores y pasajeros.

2. Científicos y analistas de datos (cientos de usuarios): estos son los


analistas y científicos repartidos en diferentes grupos funcionales que necesitan
datos para ayudar a ofrecer las mejores experiencias posibles de transporte y
entrega a nuestros usuarios, por ejemplo, cuando pronostican la demanda de
pasajeros para el futuro. Prueba nuestros servicios.

3. Equipos de ingeniería (cientos de usuarios): los ingenieros de toda la


empresa se centraron en crear aplicaciones de datos automatizadas, como
nuestras plataformas de detección de fraudes y de incorporación de
controladores.

La primera generación de nuestro almacén de datos analíticos se centró en


agregar todos los datos de Uber en un solo lugar y en optimizar el acceso a los
datos. Para el primero, decidimos usar Vertica como nuestro software de
almacenamiento de datos debido a su diseño rápido, escalable y orientado a
columnas. También desarrollamos múltiples trabajos ad hoc ETL (Extraer,
Transformar y Cargar) que copiaron datos de diferentes fuentes (es decir, AWS
S3, bases de datos OLTP, registros de servicios, etc.) en Vertica. Para lograr
esto último, estandarizamos SQL como la interfaz de nuestra solución y creamos
un servicio de consultas en línea para aceptar consultas de los usuarios y
enviarlas al motor de consultas subyacente. La Figura 2, a continuación, muestra
este almacén de datos analíticos:

Figura 2: La primera generación de la plataforma Big Data de Uber nos permitió


agregar todos los datos de Uber en un solo lugar y proporcionar una interfaz SQL
estándar para que los usuarios accedan a los datos.

El lanzamiento de nuestro primer servicio de almacenamiento de datos fue un


gran éxito para los ingenieros de toda la empresa. Por primera vez, los usuarios
tenían una visión global y podían acceder a todos los datos en un solo lugar.
Esto dio como resultado una gran cantidad de nuevos equipos que utilizan el
análisis de datos como base para sus decisiones tecnológicas y de producto. En
unos pocos meses, el tamaño de nuestros datos analíticos aumentó a decenas
de terabytes y el número de usuarios aumentó a varios cientos.

El uso de SQL como una interfaz estándar simple permitió a los operadores de
la ciudad interactuar fácilmente con los datos sin conocer las tecnologías
subyacentes. Además, diferentes equipos de ingeniería comenzaron a construir
servicios y productos adaptados a las necesidades de los usuarios que fueron
informados por estos datos (es decir, uberPool, precios iniciales, etc.) y se
formaron nuevos equipos para usar y servir mejor estos datos (es decir, nuestro
aprendizaje automático y equipos de experimentación).

Limitaciones

Por otro lado, el uso generalizado de nuestro almacén de datos y los datos
entrantes revelaron algunas limitaciones. Como los datos se ingirieron a través
de trabajos ETL ad hoc y carecíamos de un mecanismo de comunicación de
esquema formal, la confiabilidad de los datos se convirtió en una preocupación.
La mayoría de nuestros datos fuente estaban en formato JSON, y los trabajos
de ingestión no eran resistentes a los cambios en el código del productor.

A medida que nuestra empresa creció, la ampliación de nuestro almacén de


datos se volvió cada vez más costosa. Para reducir los costos, comenzamos a
eliminar datos antiguos y obsoletos para liberar espacio para nuevos datos.
Además de esto, gran parte de nuestra plataforma Big Data no era escalable
horizontalmente, ya que el objetivo principal era desbloquear la necesidad
comercial crítica de acceso o visualización centralizada de datos y simplemente
no había tiempo suficiente para garantizar que todas las partes fueran escalables
horizontalmente. Nuestro almacén de datos se estaba utilizando efectivamente
como un lago de datos, acumulando todos los datos en bruto, así como
realizando todos los modelos de datos y sirviendo los datos.

Además, los trabajos de ETL que ingirieron datos en el almacén de datos


también fueron muy frágiles debido a la falta de un contrato formal entre los
servicios que producen los datos y los consumidores de datos posteriores (el uso
del formato flexible JSON resultó en la falta de cumplimiento del esquema para
datos fuente). Los mismos datos podrían ingerirse varias veces si diferentes
usuarios realizaran diferentes transformaciones durante la ingestión. Esto dio
lugar a una presión adicional sobre nuestras fuentes de datos ascendentes (es
decir, almacenes de datos en línea) y afectó su calidad de servicio. Además, esto
resultó en múltiples copias de casi los mismos datos almacenados en nuestro
almacén, aumentando aún más los costos de almacenamiento. Y en el caso de
los problemas de calidad de los datos, el relleno requería mucho tiempo y trabajo
porque los trabajos de ETL eran ad hoc y dependientes de la fuente, y las
proyecciones de datos y la transformación se realizaron durante la ingestión.
También fue difícil ingerir nuevos conjuntos de datos y tipos debido a la falta de
estandarización en nuestros trabajos de ingestión.

Generación 2: la llegada de Hadoop

Para abordar estas limitaciones, rediseñamos nuestra plataforma Big Data en


torno al ecosistema Hadoop. Más específicamente, presentamos un lago de
datos Hadoop donde todos los datos sin procesar se ingirieron de diferentes
almacenes de datos en línea solo una vez y sin transformación durante la
ingestión. Este cambio de diseño redujo significativamente la presión sobre
nuestros almacenes de datos en línea y nos permitió hacer la transición de
trabajos de ingesta ad hoc a una plataforma de ingesta escalable. Para que los
usuarios puedan acceder a los datos en Hadoop, introdujimos Presto para
habilitar consultas interactivas de usuarios ad hoc, Apache Spark para facilitar el
acceso programático a datos sin procesar (en formatos SQL y no SQL) y Apache
Hive para servir como el caballo de batalla para consultas extremadamente
grandes. Estos motores de consulta diferentes permitieron a los usuarios utilizar
las herramientas que mejor satisfacían sus necesidades, haciendo que nuestra
plataforma fuera más flexible y accesible.
Para mantener la plataforma escalable, nos aseguramos de que todo el
modelado y la transformación de los datos solo ocurrieran en Hadoop, lo que
permite un rápido llenado y recuperación cuando surgen problemas. Solo las
tablas modeladas más críticas (es decir, aquellas aprovechadas por los
operadores de la ciudad en tiempo real para ejecutar consultas SQL puras y
rápidas) se transfirieron a nuestro almacén de datos. Esto redujo
significativamente el costo operativo de ejecutar un gran almacén de datos y al
mismo tiempo dirigir a los usuarios a motores de consulta basados en Hadoop
que fueron diseñados teniendo en cuenta sus necesidades específicas.
También aprovechamos el formato de archivo columnar estándar de Apache
Parquet, lo que resultó en ahorros de almacenamiento dada la relación de
compresión mejorada y las ganancias de recursos de cómputo dado el acceso
columnar para atender consultas analíticas. Además, la perfecta integración de
Parquet con Apache Spark hizo de esta solución una opción popular para
acceder a los datos de Hadoop. La Figura 3, a continuación, resume la
arquitectura de nuestra plataforma Big Data de segunda generación:
Figura 3: La segunda generación de nuestra plataforma Big Data aprovechó Hadoop para
permitir el escalado horizontal. Al incorporar tecnologías como Parquet, Spark y Hive, se
ingirieron, almacenaron y sirvieron decenas de petabytes de datos.

Además de incorporar un lago de datos Hadoop, también hicimos que todos los
servicios de datos en este ecosistema sean escalables horizontalmente,
mejorando así la eficiencia y la estabilidad de nuestra plataforma Big Data. En
particular, tener esta escalabilidad horizontal universal para abordar las
necesidades comerciales inmediatas nos permitió concentrar nuestra energía en
la construcción de la próxima generación de la plataforma de datos en lugar de
la resolución de problemas ad hoc.

A diferencia de la primera generación de nuestra plataforma en la que las


canalizaciones de datos eran vulnerables a los cambios en el formato de datos
aguas arriba, nuestra segunda iteración nos permitió esquematizar todos los
datos, haciendo la transición de JSON a Parquet para almacenar el esquema y
los datos juntos. Para lograr esto, creamos un servicio de esquema central para
recopilar, almacenar y servir esquemas, así como diferentes bibliotecas de
clientes para integrar diferentes servicios con este servicio de esquema central.
Los trabajos de ingesta de datos ad hoc frágiles se reemplazaron con una
plataforma estándar para transferir todos los datos de origen en su formato
original anidado al lago de datos Hadoop. Cualquier operación requerida y
transformación de los datos ocurrió después de la ingestión a través de trabajos
por lotes escalables horizontalmente en Hadoop.

Con el negocio de Uber continuando escalando a la velocidad de la luz, pronto


tuvimos decenas de petabytes de datos. Diariamente, se agregaron decenas de
terabytes de datos nuevos a nuestro lago de datos, y nuestra plataforma Big Data
creció a más de 10,000 vcores con más de 100,000 trabajos por lotes en
ejecución en un día determinado. Esto dio como resultado que nuestro lago de
datos Hadoop se convirtiera en la fuente centralizada de la verdad para todos los
datos analíticos de Uber.

Limitaciones

A medida que la compañía continuó escalando y con decenas de petabytes de


datos almacenados en nuestro ecosistema, enfrentamos un nuevo conjunto de
desafíos.
Para comenzar, la cantidad masiva de archivos pequeños almacenados en
nuestro HDFS (como resultado de la ingestión de más datos, así como de más
usuarios que escriben trabajos por lotes ad hoc que generaron aún más datos
de salida) comenzaron a agregar presión adicional sobre los Nodos de Nombre
HDFS. Además de eso, la latencia de datos aún estaba lejos de lo que nuestro
negocio necesitaba. Los usuarios solo podían acceder a los datos nuevos una
vez cada 24 horas, lo que era demasiado lento para tomar decisiones en tiempo
real. Si bien mover ETL y modelar en Hadoop hizo que este proceso fuera más
escalable, estos pasos todavía eran cuellos de botella, ya que estos trabajos de
ETL tenían que recrear toda la tabla modelada en cada ejecución. Además del
problema, tanto la ingestión de los nuevos datos como el modelado de la tabla
derivada relacionada se basaron en la creación de nuevas instantáneas de todo
el conjunto de datos y el intercambio de las tablas antiguas y nuevas para
proporcionar a los usuarios acceso a datos nuevos. Los trabajos de ingestión
tuvieron que volver al almacén de datos de origen, crear una nueva instantánea
e ingerir o convertir todo el conjunto de datos en archivos de parquet de
columnas consumibles durante cada ejecución. Con el crecimiento de nuestros
almacenes de datos, estos trabajos podrían tomar más de veinte horas con la
ejecución de más de 1,000 ejecutores de Spark.

Una gran parte de cada trabajo implicaba la conversión de datos históricos y


nuevos de la última instantánea. Si bien solo se agregaron más de 100 gigabytes
de datos nuevos cada día para cada tabla, cada ejecución del trabajo de
ingestión tuvo que convertir todo el conjunto de datos de más de 100 terabytes
para esa tabla específica. Esto también fue cierto para ETL y trabajos de
modelado que recrearon nuevas tablas derivadas en cada ejecución. Estos
trabajos tuvieron que depender de la ingesta basada en instantáneas de los
datos de origen debido a la alta proporción de actualizaciones en los datos
históricos. Por naturaleza, nuestros datos contienen muchas operaciones de
actualización (es decir, calificaciones del conductor y del conductor o ajustes de
tarifas de soporte unas pocas horas o incluso días después de un viaje
completado). Dado que HDFS y Parquet no admiten actualizaciones de datos,
todos los trabajos de ingesta necesarios para crear nuevas instantáneas a partir
de los datos de origen actualizados, ingieren la nueva instantánea en Hadoop, la
convierten en formato Parquet y luego intercambian las tablas de salida para ver
los nuevos datos. La Figura 4, a continuación, resume cómo estas ingestas de
datos basadas en instantáneas se movieron a través de nuestra plataforma Big
Data:

Figura 4: Si bien Hadoop permitió el almacenamiento de varios petabytes de


datos en nuestra plataforma Big Data, la latencia para los nuevos datos aún se
mantuvo durante un día, un retraso debido a la ingesta basada en instantáneas
de tablas de origen grandes y ascendentes que demoran varias horas en llegar.
proceso.

Generación 3: reconstrucción de nuestra plataforma de Big Data a largo plazo

A principios de 2017, nuestra plataforma de Big Data fue utilizada por equipos
de ingeniería y operaciones en toda la empresa, lo que les permitió acceder a
datos nuevos e históricos, todo en un solo lugar. Los usuarios pueden acceder
fácilmente a los datos en Hive, Presto, Spark, Vertica, Notebook y más
opciones de almacén a través de un único portal de interfaz de usuario
adaptado a sus necesidades. Con más de 100 petabytes de datos en HDFS,
100,000 vcores en nuestro clúster de cómputo, 100,000 consultas de Presto
por día, 10,000 trabajos de Spark por día y 20,000 consultas de Hive por día,
nuestra arquitectura de análisis de Hadoop estaba golpeando las limitaciones
de escalabilidad y muchos servicios se vieron afectados por altas latencia de
datos.

Afortunadamente, dado que nuestra infraestructura subyacente era escalable


horizontalmente para abordar las necesidades comerciales inmediatas, tuvimos
suficiente tiempo para estudiar nuestro contenido de datos, patrones de acceso
a datos y requisitos específicos del usuario para identificar las preocupaciones
más urgentes antes de construir la próxima generación. Nuestra investigación
reveló cuatro puntos principales de dolor:

1. Limitación de escalabilidad de HDFS: muchas empresas que confían en


HDFS enfrentan este problema para escalar sus infraestructuras de big data.
Por diseño, HDFS se ve afectado por su capacidad NameNode, por lo que
almacenar grandes cantidades de archivos pequeños puede afectar
significativamente el rendimiento. Esta limitación generalmente ocurre cuando
el tamaño de los datos crece más allá de diez petabytes y se convierte en un
problema real más allá de 50-100 petabytes. Afortunadamente, existen
soluciones relativamente sencillas para escalar HDFS de unas pocas decenas
a unos pocos cientos de petabytes, por ejemplo, aprovechando ViewFS y
utilizando la Federación HDFS NameNode. Al controlar la cantidad de archivos
pequeños y mover diferentes partes de nuestros datos a grupos separados (por
ejemplo, los registros de la aplicación HBase y Yarn se movieron a un grupo
HDFS separado), pudimos mitigar esta limitación de HDFS.

2. Datos más rápidos en Hadoop: el negocio de Uber opera en tiempo real y,


como tal, nuestros servicios requieren acceso a datos lo más actualizados
posible. Como resultado, la latencia de datos de 24 horas fue demasiado lenta
para muchos casos de uso y hubo una gran demanda de entrega de datos más
rápida. El método de ingesta basado en instantáneas de nuestra plataforma de
Big Data de segunda generación fue ineficiente y nos impidió ingerir datos con
menor latencia. Para acelerar la entrega de datos, tuvimos que rediseñar
nuestra tubería para la ingesta incremental de datos nuevos y actualizados.

3. Soporte de actualizaciones y eliminaciones en Hadoop y Parquet: los datos


de Uber contienen muchas actualizaciones, que varían en edad desde los
últimos días (p. Ej., Un piloto o un socio conductor que ajusta una tarifa de viaje
reciente) a unas pocas semanas (p. Ej., un pasajero calificando su último viaje
la próxima vez que realice un nuevo viaje) o incluso unos pocos meses (por
ejemplo, rellenando o ajustando datos pasados debido a una necesidad
comercial). Con la ingesta de datos basada en instantáneas, ingerimos una
copia nueva de los datos de origen cada 24 horas. En otras palabras, ingerimos
todas las actualizaciones a la vez, una vez al día. Sin embargo, con la
necesidad de datos más frescos e ingesta incremental, nuestra solución debe
ser capaz de admitir operaciones de actualización y eliminación de datos
existentes. Sin embargo, dado que nuestros Big Data se almacenan en HDFS y
Parquet, no es posible admitir directamente las operaciones de actualización en
los datos existentes. Por otro lado, nuestros datos contienen tablas
extremadamente anchas (alrededor de 1,000 columnas por tabla) con cinco o
más niveles de anidamiento, mientras que las consultas de los usuarios
generalmente solo tocan algunas de estas columnas, lo que nos impide usar
formatos no columnar de manera rentable camino. Para preparar nuestra
plataforma Big Data para el crecimiento a largo plazo, tuvimos que encontrar
una manera de resolver esta limitación dentro de nuestro sistema de archivos
HDFS para que también podamos admitir operaciones de actualización /
eliminación.

ETL y modelado más rápidos: al igual que la ingestión de datos sin procesar,
los trabajos de modelado y ETL se basaron en instantáneas, lo que requiere
que nuestra plataforma reconstruya las tablas derivadas en cada ejecución.
Para reducir la latencia de datos para tablas modeladas, los trabajos ETL
también debían ser incrementales. Esto requería que los trabajos de ETL
extrajeran gradualmente solo los datos modificados de la tabla de origen sin
procesar y actualicen la tabla de salida derivada anterior en lugar de reconstruir
la tabla de salida completa cada poca hora.

Introduciendo Hudi

Con los requisitos anteriores en mente, creamos Hadoop Upserts eD Incremental


(Hudi), una biblioteca de código abierto de Spark que proporciona una capa de
abstracción sobre HDFS y Parquet para admitir las operaciones de actualización
y eliminación requeridas. Hudi se puede usar desde cualquier trabajo de Spark,
es escalable horizontalmente y solo depende de HDFS para operar. Como
resultado, cualquier plataforma de Big Data que necesite soportar operaciones
de actualización / eliminación para los datos históricos puede aprovechar Hudi.

Hudi nos permite actualizar, insertar y eliminar datos existentes de Parquet en


Hadoop. Además, Hudi permite a los usuarios de datos extraer de forma
incremental solo los datos modificados, lo que mejora significativamente la
eficiencia de las consultas y permite actualizaciones incrementales de las tablas
modeladas derivadas.

Los datos sin procesar en nuestro ecosistema de Hadoop se dividen en función


del tiempo y cualquiera de las particiones antiguas puede recibir actualizaciones
en un momento posterior. Por lo tanto, para un usuario de datos o un trabajo ETL
que confía en estas tablas de datos de origen sin procesar, la única forma de
saber qué partición de fecha contiene datos actualizados es escanear toda la
tabla de origen y filtrar los registros en función de alguna noción de tiempo
conocida. Esto da como resultado una consulta computacionalmente costosa
que requiere un escaneo completo de la tabla de origen y evita que los trabajos
ETL se ejecuten con mucha frecuencia.

Con Hudi, los usuarios pueden simplemente pasar su última marca de tiempo de
punto de control y recuperar todos los registros que se han actualizado desde
entonces, independientemente de si estas actualizaciones son registros nuevos
agregados a particiones de fechas recientes o actualizaciones a datos más
antiguos (por ejemplo, un nuevo viaje que ocurre hoy versus un viaje actualizado
de hace 6 meses), sin ejecutar una consulta costosa que escanea toda la tabla
fuente.

Al usar la biblioteca Hudi, pudimos pasar de la ingesta de datos sin procesar


basada en instantáneas a un modelo de ingesta incremental que nos permite
reducir la latencia de datos de 24 horas a menos de una hora. La Figura 5, a
continuación, muestra nuestra plataforma Big Data después de la incorporación
de Hudi:

Figura 5: La tercera generación de nuestra plataforma Big Data incorpora una ingesta de
datos más rápida e incremental (utilizando nuestro marco Marmaray de código abierto),
así como un almacenamiento y servicio de datos más eficientes a través de nuestra
biblioteca Hudi de código abierto.

Ingestión genérica de datos


Hudi no es la única adición a la tercera generación de nuestra plataforma Big
Data. También formalizamos el traspaso de los cambios del almacén de datos
aguas arriba entre los equipos de almacenamiento y big data a través de
Apache Kafka. Los eventos de almacenamiento de datos ascendentes (así
como los mensajes de registro clásicos de diferentes aplicaciones y servicios)
se transmiten a Kafka con una codificación Avro unificada que incluye
encabezados de metadatos globales estándar adjuntos (es decir, marca de
tiempo, clave de fila, versión, información del centro de datos y host de origen).
Los equipos de Streaming y Big Data utilizan estos eventos de registro de
cambios de almacenamiento como sus datos de entrada de origen para su
posterior procesamiento.

Nuestra plataforma de ingestión de datos, Marmaray, se ejecuta en mini lotes y


recoge los registros de cambios de almacenamiento aguas arriba de Kafka,
aplicándolos sobre los datos existentes en Hadoop usando la biblioteca Hudi.
Como se mencionó anteriormente, Hudi admite operaciones upsert, lo que
permite a los usuarios agregar nuevos registros y actualizar o eliminar datos
históricos. Los trabajos de ingestión de Spark se ejecutan cada 10-15 minutos,
lo que proporciona una latencia de datos sin procesar de 30 minutos en
Hadoop (con margen para 1-2 fallos o reintentos en el trabajo de ingestión).
Para evitar ineficiencias resultantes de la ingesta de los mismos datos de
origen en Hadoop más de una vez, nuestra configuración no permite ninguna
transformación durante la ingestión de datos sin procesar, lo que resulta en
nuestra decisión de hacer que nuestro marco de ingestión de datos sin
procesar sea una plataforma EL en lugar de una plataforma ETL tradicional.
Según este modelo, se alienta a los usuarios a realizar las operaciones de
transformación deseadas dentro de Hadoop y en modo por lotes después de
que los datos aguas arriba lleguen a su formato anidado sin procesar.

Desde la implementación de estos cambios en nuestra plataforma Big Data,


hemos ahorrado una cantidad significativa de recursos computacionales al
evitar operaciones de ingestión innecesarias o ineficientes. La fiabilidad de
nuestros datos en bruto también ha mejorado significativamente, ya que ahora
podemos evitar transformaciones propensas a errores durante la ingestión.
Ahora, los usuarios pueden ejecutar sus transformaciones sobre los datos de
origen sin procesar utilizando cualquier motor de procesamiento de Big Data.
Además, en caso de cualquier problema, los usuarios pueden volver a ejecutar
sus transformaciones nuevamente y aun así cumplir con sus SLA utilizando
más recursos informáticos y un mayor grado de paralelismo para finalizar los
trabajos de transformación por lotes más rápido.

Modelado incremental de datos

Teniendo en cuenta la gran cantidad de almacenes de datos ascendentes que


deben ser ingeridos en Hadoop (más de 3,000 tablas de Hadoop sin procesar a
partir de 2017), también creamos una plataforma de ingesta genérica que
facilita la ingestión de datos sin procesar en Hadoop de manera unificada y
configurable. Ahora, nuestra plataforma Big Data actualiza las tablas de
Hadoop sin procesar de forma incremental con una latencia de datos de 10-15
minutos, lo que permite un acceso rápido a los datos de origen. Sin embargo,
para garantizar que las tablas modeladas también estén disponibles con baja
latencia, debemos evitar ineficiencias (es decir, recreación de tablas derivadas
completas o escaneos de tablas sin formato de fuente completa) en nuestros
trabajos de modelado ETL. De hecho, Hudi permite que los trabajos ETL
obtengan solo los datos modificados de la tabla de origen. Los trabajos de
modelado solo necesitan pasar una marca de tiempo de punto de control
durante cada ejecución iterativa al lector Hudi para recibir una secuencia de
registros nuevos o actualizados de la tabla fuente sin procesar
(independientemente de la partición de fecha en la que se almacena el registro
real).
El uso de un escritor Hudi durante un trabajo ETL nos permite actualizar
particiones antiguas en las tablas modeladas derivadas sin recrear la partición
o tabla completa. Por lo tanto, nuestros trabajos de modelado de ETL usan
lectores Hudi para obtener de forma incremental solo los datos modificados de
la tabla fuente y usan escritores Hudi para actualizar incrementalmente la tabla
de salida derivada. Ahora, los trabajos ETL también finalizan en menos de 30
minutos, proporcionando una latencia de extremo a extremo de menos de una
hora para todas las tablas derivadas en Hadoop.
Para proporcionar a los usuarios de datos de las tablas de Hadoop diferentes
opciones para acceder a todos los datos o solo a datos nuevos o actualizados,
las tablas en bruto de Hadoop que utilizan el formato de almacenamiento Hudi
proporcionan dos modos de lectura diferentes:
1. Vista del último modo. Proporciona una vista holística de toda la tabla de
Hadoop en ese momento. Esta vista incluye los últimos valores combinados
para todos los registros, así como todos los registros existentes en una tabla.
2. Vista en modo incremental. Obtiene solo los registros nuevos y actualizados
de una tabla de Hadoop específica en función de una marca de tiempo
determinada. Esta vista solo devuelve las filas que se han insertado
recientemente o se han actualizado desde el último punto de control. Además,
si una fila específica se actualiza más de una vez desde el último punto de
control, este modo devuelve todos estos valores intermedios modificados (en
lugar de solo devolver el último combinado)
La Figura 6, a continuación, muestra estas dos vistas de lectura para todas las
tablas de Hadoop almacenadas en formato de archivo Hudi:

Figura 6: Una tabla sin procesar que se está actualizando a través de Hudi Writer se
puede leer en dos modos diferentes: la última vista de modo que devuelve el último
valor para todos los registros y la vista de modo incremental que devuelve solo los
registros actualizados desde la última lectura.

Los usuarios generalmente alternan entre estas dos vistas de tabla según sus
necesidades. Cuando ejecutan una consulta ad hoc para analizar datos
basados en el último estado, utilizan la última vista de modo de la tabla (por
ejemplo, para obtener el número semanal total de viajes por ciudad en los EE.
UU.). Por otro lado, cuando un usuario tiene un trabajo iterativo o una consulta
que necesita obtener solo registros nuevos o modificados desde su última
ejecución, utiliza la vista de modo incremental. Ambas vistas están disponibles
para todas las tablas de Hadoop en todo momento, y los usuarios pueden
cambiar entre diferentes modos según sus necesidades.
Modelo de datos estandarizado
Además de proporcionar diferentes vistas de la misma tabla, también
estandarizamos nuestro modelo de datos para proporcionar dos tipos de tablas
para todos los datos sin procesar de Hadoop:
1. Tabla de historial de cambios. Contiene el historial de todos los registros de
cambios recibidos para una tabla ascendente específica. Esta tabla permite a
los usuarios escanear el historial de cambios para una tabla determinada y se
puede combinar por clave para proporcionar el último valor para cada fila.
2. Tabla de instantáneas fusionadas. Contiene la última vista fusionada de las
tablas aguas arriba. Esta tabla contiene la vista fusionada compactada de todos
los registros de cambios históricos recibidos por clave.
La Figura 7, a continuación, muestra cómo se generan las diferentes tablas sin
procesar de Hive para un almacén de datos de origen ascendente específico
utilizando la secuencia de registros de cambios dados:

Figura 7: La estandarización de nuestro modelo de datos Hive mejoró la calidad de los


datos para todo nuestro ecosistema de Big Data. Este modelo incorpora una tabla de
instantáneas combinadas que contiene los últimos valores para cada fila_clave, así como
una tabla de historial de cambios que contiene el historial de todos los cambios de valor
por cada fila_clave.

Sin embargo, la secuencia de registros de cambios puede contener o no la fila


completa (todas las columnas) para una clave determinada. Si bien las tablas
de instantáneas fusionadas siempre proporcionan todas las columnas para una
clave específica, la tabla del historial de registro de cambios puede ser escasa
si el flujo ascendente de registros de cambios solo proporciona registros de
cambios de filas parciales, una funcionalidad que mejora la eficiencia al evitar
reenviar toda la fila cuando solo una o unas pocas Se cambian los valores de
columna limitados. Si los usuarios desean obtener los valores modificados de la
tabla del historial del registro de cambios y unirlos contra la tabla de
instantáneas fusionadas para crear la fila completa de datos, también incluimos
la partición de fecha de la misma clave de la tabla de instantáneas fusionadas
en la tabla del historial del registro de cambios. Esto permite que las dos tablas
se unan de manera más eficiente en una partición específica al evitar un
escaneo completo de la tabla de instantáneas fusionadas al unir las dos.

La Figura 8, a continuación, resume la relación entre los diferentes


componentes de nuestra plataforma Big Data:
Figura 8: La construcción de una plataforma de transferencia de datos más extensible
nos permitió agregar fácilmente todas las canalizaciones de datos de una manera
estándar en un solo servicio, así como admitir la conectividad de cualquier a cualquier
fuente de datos y sumidero de datos.

Generación 4: ¿Qué sigue?


Desde el lanzamiento de la tercera generación de nuestra plataforma Big Data
en 2017, los usuarios de toda la empresa pueden acceder de manera rápida y
confiable a los datos en Hadoop, pero siempre hay espacio para crecer. A
continuación resumimos nuestros esfuerzos continuos para mejorar la
plataforma Big Data de Uber para mejorar la calidad, la latencia, la eficiencia, la
escalabilidad y la confiabilidad de los datos.

Calidad de los datos

Para mejorar la calidad de los datos, identificamos dos áreas clave para la
mejora. Primero, queremos evitar datos que no se ajusten al esquema cuando
algunos de los almacenes de datos ascendentes no imponen o verifican
obligatoriamente el esquema de datos antes del almacenamiento (por ejemplo,
almacenar un valor clave donde el valor es un blob JSON). Esto da como
resultado que ingresen datos incorrectos a nuestro ecosistema Hadoop, lo que
afecta a todos los usuarios intermedios que también dependen de estos datos.
Para evitar una afluencia de datos incorrectos, estamos haciendo la transición
de todos los almacenes de datos ascendentes para realizar verificaciones de
esquema obligatorias en el contenido de datos y rechazar las entradas de
datos si hay algún problema (por ejemplo, no confirmar con el esquema) con
los datos.
La segunda área que encontramos problemática fue la calidad del contenido
real de los datos. Si bien el uso de esquemas garantiza que los datos
contengan los tipos de datos correctos, no verifican los valores de datos reales
(por ejemplo, un número entero en lugar de un número positivo entre [0,150]).
Para mejorar la calidad de los datos, estamos ampliando nuestro servicio de
esquemas para admitir comprobaciones semánticas. Estas verificaciones
semánticas (en otras palabras, tipos de datos específicos de Uber) nos
permiten agregar restricciones adicionales en el contenido de datos real más
allá de la verificación básica de tipos estructurales.

Latencia de datos

Nuestro objetivo es reducir la latencia de datos sin procesar en Hadoop a cinco


minutos y la latencia de datos para tablas modeladas a diez minutos. Esto
permitirá que más casos de uso se alejen del procesamiento de flujo a un
procesamiento de mini lotes más eficiente que use los datos incrementales de
Hudi.

También estamos ampliando nuestro proyecto Hudi para admitir un modo de


vista adicional, que incluirá la vista optimizada de lectura existente, así como
una nueva vista en tiempo real que muestra datos con una latencia de solo
unos minutos. Esta vista en tiempo real se basa en una solución de código
abierto (y parte de Hudi) que llamamos Merge-On-Read o Hudi 2.0.

Eficiencia de datos

Para mejorar la eficiencia de los datos, nos estamos alejando de depender de


hardware dedicado para cualquiera de nuestros servicios y hacia la
dockerización de servicios. Además, estamos unificando todos nuestros
programadores de recursos dentro y en todo nuestro ecosistema de Hadoop para
cerrar la brecha entre nuestros servicios de Hadoop y los que no son de datos
en toda la empresa. Esto permite que todos los trabajos y servicios se programen
de manera unificada, independientemente del medio en el que se ejecutarán. A
medida que Uber crece, la localidad de datos será una gran preocupación para
las aplicaciones de Hadoop, y un exitoso administrador de recursos unificado
puede reunir a todos los programadores existentes. (es decir, hilo, mesos y
miríada).

Escalabilidad y confiabilidad

Como parte de nuestro esfuerzo por mejorar la escalabilidad y confiabilidad de


nuestra plataforma, identificamos varios problemas relacionados con posibles
casos límite. Si bien nuestra plataforma de ingestión se desarrolló como un
modelo genérico y conectable, la ingestión real de datos ascendentes aún
incluye muchas configuraciones de tuberías dependientes de la fuente, lo que
hace que la tubería de ingestión sea frágil y aumente los costos de
mantenimiento de operar varios miles de estas tuberías.

Para garantizar que hayamos unificado la ingesta de datos, independientemente


de la fuente de datos, hemos iniciado un proyecto en colaboración con el equipo
de almacenamiento de datos de Uber para unificar el contenido, el formato y los
metadatos de los registros de cambios de todas las fuentes de datos
ascendentes, independientemente de su composición tecnológica. Este proyecto
garantizará que la información sobre estas tecnologías específicas de flujo
ascendente solo sea un metadato adicional agregado al valor real del registro de
cambios (en lugar de tener contenido y metadatos de registro de cambios
totalmente diferentes para diferentes fuentes de datos) y la ingestión de datos
ocurrirá independientemente de la fuente ascendente.

Finalmente, nuestra próxima versión de Hudi nos permitirá generar archivos


Parquet mucho más grandes (más de un gigabyte en comparación con nuestros
128 megabytes actuales) de forma predeterminada en unos minutos para todas
nuestras fuentes de datos. También eliminará cualquier sensibilidad en torno a
la proporción de actualizaciones versus inserciones. Hudi 1.0 se basa en una
técnica llamada copia en escritura que reescribe todo el archivo Parquet de
origen siempre que haya un registro actualizado. Esto aumenta
significativamente la amplificación de escritura, especialmente cuando aumenta
la proporción de actualización a inserción, y evita la creación de archivos Parquet
más grandes en HDF. La nueva versión de Hudi está diseñada para superar esta
limitación almacenando el registro actualizado en un archivo delta separado y
fusionándolo asincrónicamente con el archivo Parquet base en función de una
política determinada (por ejemplo, cuando hay suficiente cantidad de datos
actualizados para amortizar el costo de reescribir un archivo base grande de
Parquet). Tener los datos de Hadoop almacenados en archivos de Parquet más
grandes, así como una plataforma de ingesta de datos independiente de la fuente
más confiable permitirá que nuestra plataforma de datos analíticos continúe
creciendo en los próximos años a medida que el negocio prospere.
Avanzando
La organización de datos de Uber es una colaboración interfuncional entre la
Plataforma de datos, la Fundación de datos, la Plataforma de transmisión y en
tiempo real, y los equipos de Big Data para construir las bibliotecas necesarias y
los servicios distribuidos que admiten la infraestructura de datos analíticos de
Uber. Si le interesa trabajar en desafíos de Big Data que alteran los límites de la
escala, considere solicitar un puesto en nuestros equipos con sede en San
Francisco y Palo Alto.

También podría gustarte