IO Remoto de Alto Rendimiento con NVIDIA KviKIO
Las cargas de trabajo que procesan grandes cantidades de datos, especialmente las que se ejecutan en la nube, a menudo utilizan un servicio de almacenamiento de objetos (S3, Google Cloud Storage, Azure Blob Storage, etc.) como fuente de datos. Los servicios de almacenamiento de objetos pueden almacenar y servir grandes cantidades de datos, pero obtener el mejor rendimiento puede requerir adaptar su carga de trabajo a cómo se comportan los almacenes de objetos remotos. Esta publicación es para usuarios de RAPIDS que desean leer o escribir datos en el almacenamiento de objetos lo más rápido posible para que IO no bloquee su carga de trabajo. Parte de su conocimiento sobre cómo se comportan los sistemas de archivos locales se traduce en almacenes de objetos remotos, pero son fundamentalmente diferentes. Probablemente la mayor diferencia entre los dos, al menos para las cargas de trabajo de análisis de datos, es que las operaciones de lectura y escritura en el almacenamiento de objetos tienen latencia más alta y más variable. Cada servicio de almacenamiento tiene su propio conjunto de mejores prácticas y pautas de rendimiento (AWS, Azure). Aquí, weizll dar algunas pautas generales que se centran en las cargas de trabajo de análisis de datos. Ubicación Colocar sus nodos de cómputo cerca del servicio de almacenamiento (idealmente, en la misma región de la nube) le dará la red más rápida y confiable entre las máquinas que ejecutan su carga de trabajo y las máquinas que sirven los datos. Y, al final del día, la transferencia estará limitada por la velocidad de la luz, por lo que minimizar la distancia física no duele. Formato de archivo “Los formatos de archivo Cloud-native” se han desarrollado para funcionar bien con el almacenamiento de objetos. Estos formatos de archivo generalmente proporcionan un acceso rápido y fácil a los metadatos (que incluye información de alto nivel como los nombres de columna o los tipos de datos, e información de nivel inferior como dónde se encuentran los subconjuntos de datos específicos del archivo). Parquet Apache, Zarr, y GeoTIFF Optimizado en la Nube son algunos ejemplos de formatos de archivo nativos de la nube para varios tipos de datos. Porque los servicios de almacenamiento de objetos generalmente admiten solicitudes de rango, clientes (como cuDF) puede leer los metadatos y luego descargar solo los datos que realmente necesitas. Por ejemplo, cuDF puede leer solo unas pocas columnas de un archivo de parquet con muchas columnas, o un cliente de Zarr puede leer un solo fragmento de una gran matriz n-dimensional. Estas lecturas se realizan en solo unas pocas solicitudes HTTP, y sin necesidad de descargar un montón de datos extraños que simplemente se filtran. Tamaño del archivo Debido a que cada operación de lectura requiere (al menos) una petición HTTP, weedd prefiere amortizar la sobrecarga de cada petición HTTP sobre un número razonablemente grande de bytes. Si controla el proceso de escritura de datos, querrá asegurarse de que los archivos sean lo suficientemente grandes como para que sus tareas de procesamiento posteriores obtengan un buen rendimiento. El valor óptimo depende de su carga de trabajo, pero en algún lugar de las docenas a cientos de MB es común para los archivos de parquet (ver más abajo para algunos ejemplos específicos). Dicho esto, deberá tener cuidado con la forma en que el tamaño del archivo interactúa con la siguiente herramienta de nuestro kit: concurrencia. Concurrencia El uso de concurrencia para descargar múltiples blobs (o múltiples piezas de un solo blob) al mismo tiempo es esencial para obtener un buen rendimiento de un servicio de almacenamiento remoto. Ya que es un remoto servicio, su proceso va a pasar algún tiempo (quizás mucho tiempo) esperando no hacer nada. Esta espera abarca el tiempo entre el momento en que se envía la solicitud HTTP y la respuesta recibida. Durante este tiempo, esperamos a que la red lleve la solicitud, el servicio de almacenamiento la procese y envíe la respuesta, y la red lleve la respuesta (posiblemente grande). Mientras que partes de esa escala de ciclo de solicitud/respuesta con la cantidad de datos involucrados, otras partes son solo gastos generales fijos. Los servicios de almacenamiento de objetos están diseñados para manejar muchas solicitudes concurrentes. Podemos combinar eso con el hecho de que cada solicitud implica algún tiempo esperando no hacer nada, para hacer muchas solicitudes concurrentes para aumentar nuestro rendimiento general. En Python, esto se haría típicamente usando un piscina de hilo: pool =concurrent.futures.ThreadPoolExecutor()futures =pool.map(request_chunk, chunks) O con asincio: tasks =[request_chunk_async(chunk) forchunk inchunks]awaitasyncio.gather(*tasks) Podemos tener muchas lecturas esperando sin hacer nada al mismo tiempo, lo que mejora nuestro rendimiento. Debido a que cada hilo/tarea no está haciendo nada en su mayoría, está bien tener más hilos/tareas de las que su máquina tiene núcleos. Dadas las suficientes solicitudes concurrentes, eventualmente saturará su servicio de almacenamiento, que tiene algunas solicitudes por segundo y objetivos de ancho de banda que intenta cumplir. Pero esos objetivos son altos; por lo general, necesitará muchas máquinas para saturar el servicio de almacenamiento y debería lograr un rendimiento muy alto. Bibliotecas Todo lo anterior se aplica esencialmente a cualquier biblioteca que haga IO remoto desde un servicio de almacenamiento de objetos. En el contexto de RAPIDS, NVIDIA KviKIO es notable porque Como se mencionó en el Anuncio de lanzamiento de RADIDS 24.12, KvikIO puede lograr un rendimiento impresionante al leer desde S3. Echemos un vistazo a algunos puntos de referencia para ver cómo funciona. Puntos de referencia Cuando lee un archivo, KvikIO divide esa lectura en lecturas más pequeñas de kvikio.defaults.task_size bytes. Hace esas solicitudes de lectura en paralelo usando un grupo de hilos con kvikio.defaults.num_threads trabajadores. Estos pueden controlarse utilizando las variables de entorno KVIKIO_TASK_SIZE y KVIKIO_NTHREADS, o a través de Python con: with kvikio.defaults.set_num_threads(num_threads), kvikio.defaults.set_task_size(size): … Ver Configuración de tiempo de ejecución para más. Este gráfico muestra el rendimiento, en megabits por segundo, de leer una gota de 1 GB S3 a g4dn instancia EC2 en la misma región para varios tamaños de la agrupación de hilos (más alto es mejor). Menos hilos (menos de cuatro) logran un rendimiento más bajo y tardan más en leer el archivo. Más subprocesos (64, 128, 256) logran un mayor rendimiento al paralelizar las solicitudes al
IO Remoto de Alto Rendimiento con NVIDIA KviKIO Leer más »








