paint-brush
El diseño e implementación de Presto Local Cache en Uberpor@bin-fan
686 lecturas
686 lecturas

El diseño e implementación de Presto Local Cache en Uber

por Bin Fan2022/06/03
Read on Terminal Reader
Read this story w/o Javascript

Demasiado Largo; Para Leer

En el blog anterior, presentamos los casos de uso de Presto de Uber y cómo colaboramos para implementar el caché local de Alluxio para superar diferentes desafíos en la aceleración de las consultas de Presto. La segunda parte analiza las mejoras en los metadatos de la memoria caché local.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail

Coin Mentioned

Mention Thumbnail
featured image - El diseño e implementación de Presto Local Cache en Uber
Bin Fan HackerNoon profile picture


En el blog anterior, presentamos los casos de uso de Presto de Uber y cómo colaboramos para implementar el caché local de Alluxio para superar diferentes desafíos en la aceleración de las consultas de Presto. La segunda parte analiza las mejoras en los metadatos de la memoria caché local.

Metadatos de nivel de archivo para caché local

Motivación

Primero, queremos evitar el almacenamiento en caché obsoleto. Los marcos de terceros pueden cambiar los archivos de datos subyacentes. Tenga en cuenta que esta situación puede ser rara en las tablas de Hive pero muy común en las tablas de Hudi.


En segundo lugar, las lecturas diarias de datos no duplicados de HDFS pueden ser grandes, pero no tenemos suficiente espacio en caché para almacenar en caché todos los datos. Por lo tanto, podemos introducir la gestión de cuotas con ámbito estableciendo una cuota para cada tabla.


En tercer lugar, los metadatos deben poder recuperarse después de reiniciar el servidor. Hemos almacenado metadatos en la caché local en la memoria en lugar del disco, lo que hace que sea imposible recuperar los metadatos cuando el servidor está inactivo y se reinicia.

Enfoque de alto nivel

Por lo tanto, proponemos los metadatos de nivel de archivo, que contienen y conservan la hora de la última modificación y el alcance de cada archivo de datos que almacenamos en caché. El almacén de metadatos a nivel de archivo debe ser persistente en el disco para que los datos no desaparezcan después de reiniciar.


Con la introducción de metadatos a nivel de archivo, habrá múltiples versiones de los datos. Se genera una nueva marca de tiempo cuando se actualizan los datos, correspondiente a una nueva versión. Se crea una nueva carpeta que almacena la nueva página correspondiente a esta nueva marca de tiempo. Al mismo tiempo, intentaremos eliminar la marca de tiempo anterior.

Estructura de metadatos y datos de caché

Como se muestra arriba, tenemos dos carpetas correspondientes a dos marcas de tiempo: timestamp1 y timestamp2. Por lo general, cuando el sistema se está ejecutando, no habrá dos marcas de tiempo simultáneamente porque eliminaremos la marca de tiempo anterior1 y conservaremos solo la marca de tiempo2. Sin embargo, en el caso de un servidor ocupado o alta concurrencia, es posible que no podamos eliminar la marca de tiempo a tiempo, en cuyo caso es posible que tengamos dos marcas de tiempo al mismo tiempo. Además, mantenemos un archivo de metadatos que contiene la información del archivo en formato protobuf y la marca de tiempo más reciente. Esto asegura que el caché local de Alluxio solo lea datos de la última marca de tiempo. Cuando el servidor se reinicia, la información de la marca de tiempo se lee del archivo de metadatos para que la cuota y la hora de la última modificación se puedan administrar correctamente.


Conciencia de metadatos

Contexto de caché

Dado que Alluxio es una solución de almacenamiento en caché genérica, todavía necesita el motor de cómputo, como Presto, para pasar los metadatos a Alluxio. Por lo tanto, en el sitio de Presto, usamos HiveFileContext. Para cada archivo de datos de la tabla Hive o la tabla Hudi, Presto crea un HiveFileContext. Alluxio hace uso de esta información al abrir un archivo de Presto.


Al llamar a openFile, Alluxio crea una nueva instancia de PrestoCacheContext, que contiene HiveFileContext y tiene el alcance (cuatro niveles: base de datos, esquema, tabla, partición), cuota, identificador de caché (es decir, el valor md5 de la ruta del archivo) y otra información. Pasaremos este contexto de caché al sistema de archivos local. Alluxio puede así gestionar metadatos y recopilar métricas.


Agregación de métricas por consulta en el lado de Presto

Además de pasar datos de Presto a Alluxio, también podemos volver a llamar a Presto. Al realizar operaciones de consulta, conoceremos algunas métricas internas, como cuántos bytes de datos leídos alcanzaron el caché y cuántos bytes de datos se leyeron del almacenamiento HDFS externo.

Como se muestra a continuación, pasamos HiveFileContext que contiene PrestoCacheContext al sistema de archivos de caché local (LocalCacheFileSystem), después de lo cual el sistema de archivos de caché local vuelve a llamar (IncremetCounter) al CacheContext. Luego, esta cadena de devolución de llamada continuará hasta HiveFileContext y luego hasta RuntimeStats.


En Presto, RuntimeStats se utiliza para recopilar información de métricas al ejecutar consultas para que podamos realizar operaciones de agregación. Después de eso, podemos ver la información sobre el sistema de archivos de caché local en la interfaz de usuario de Presto o en el archivo JSON. Podemos hacer que Alluxio y Presto trabajen en estrecha colaboración con el proceso anterior. Del lado de Presto, tenemos mejores estadísticas; en el lado de Alluxio, tenemos una imagen más clara de los metadatos.

Trabajo futuro

La optimización del rendimiento

Debido a que el proceso de devolución de llamada descrito anteriormente hace que el ciclo de vida de CacheContext crezca considerablemente, hemos encontrado algunos problemas con el aumento de la latencia de GC, que estamos trabajando para solucionar.

Adoptar caché semántica (SC)

Implementaremos Semantic Cache (SC) en función de los metadatos a nivel de archivo que proponemos. Por ejemplo, podemos guardar las estructuras de datos en archivos Parquet u ORC, como pie de página, índice, etc.

Deserialización más eficiente

Para lograr una deserialización más eficiente, usaremos flatbuf en lugar de protobuf. Aunque protobuf se usa en la fábrica de ORC para almacenar metadatos, descubrimos que los metadatos de ORC aportan más del 20-30 % del uso total de la CPU en la colaboración de Alluxio con Facebook. Por lo tanto, planeamos reemplazar el protobuf existente con un flatbuf para almacenar caché y metadatos, lo que se espera que mejore significativamente el rendimiento de la deserialización.


Para resumir, junto con el blog anterior, esta serie de blogs de dos partes comparte cómo creamos una nueva capa de almacenamiento en caché de los datos calientes necesarios para nuestra flota de Presto basada en una colaboración de código abierto reciente entre las comunidades de Presto y Alluxio en Uber. Este enfoque arquitectónicamente simple y limpio puede reducir significativamente la latencia de HDFS con SSD administrado y programación de afinidad suave basada en hashing consistente. Únase a más de 9000 miembros en nuestro canal de slack de la comunidad para obtener más información.

Sobre los autores

Chen Liang es ingeniero de software sénior en el equipo de análisis interactivo de Uber y se centra en Presto. Antes de unirse a Uber, Chen era ingeniero de software en la plataforma Big Data de LinkedIn. Chen también es committer y miembro de PMC de Apache Hadoop. Chen tiene dos maestrías de la Universidad de Duke y la Universidad de Brown.


El Dr. Beinan Wang es ingeniero de software de Alluxio y es el encargado de confirmar PrestoDB. Antes de Alluxio, fue líder técnico del equipo de Presto en Twitter y creó sistemas SQL distribuidos a gran escala para la plataforma de datos de Twitter. Tiene doce años de experiencia trabajando en la optimización del rendimiento, el almacenamiento en caché distribuido y el procesamiento de datos de volumen. Recibió su Ph.D. en ingeniería informática de la Universidad de Syracuse en la verificación del modelo simbólico y la verificación del tiempo de ejecución de los sistemas distribuidos.


También publicado aquí.