Descargar un objeto grande en Cloud Storage de forma secuencial a través de una sola conexión puede dejar sin usar el ancho de banda de red disponible. Si divides un objeto en segmentos de rango de bytes llamados bandas y lees esos segmentos de forma simultánea, puedes mejorar la capacidad de procesamiento de descarga de objetos grandes con las bibliotecas cliente de Cloud para Rust.
En este documento, se muestra cómo propagar objetos de prueba grandes con la
composición de objetos, descargar rangos de bytes de forma simultánea con
ReadRange::segment y escribir bandas en un archivo local con compensaciones fijas. Si
es la primera vez que usas la biblioteca cliente, consulta
Usa Cloud Storage con Rust primero.
Antes de comenzar
Antes de ejecutar el código de este documento, completa los siguientes requisitos previos:
- Crea o selecciona un proyecto deGoogle Cloud con la facturación habilitada.
- Crea un bucket de Cloud Storage de prueba dedicado en tu proyecto.
- Configura las credenciales predeterminadas de la aplicación para tu entorno.
- Otorga a tu principal un rol de Identity and Access Management (IAM) con permiso para
leer, escribir, redactar y borrar objetos en el bucket, como Administrador de almacenamiento
(
roles/storage.admin).
Dependencias
Agrega la biblioteca cliente de Cloud Storage y los crates de compatibilidad a tu
archivo Cargo.toml:
cargo add google-cloud-storage google-cloud-gax anyhow bytes futures
cargo add tokio --features macros,rt-multi-thread
Crea objetos de prueba grandes
Para probar las descargas divididas sin subir gigabytes de datos a través de la red,
sube un objeto de origen pequeño y usa la operación de composición de Cloud Storage
para concatenar copias del lado del servidor. Dentro de una
función asíncrona seed que acepte client, control y bucket_name
en el formato projects/_/buckets/BUCKET_ID, completa los
siguientes pasos:
Para hacer referencia a objetos existentes en solicitudes de composición, importa
SourceObject:Sube un objeto de origen de 1 MiB llamado
1MiB.txt:Para crear un objeto de 32 MiB llamado
32MiB.txt, concatena 32 copias de1MiB.txten el servidor:Para crear un objeto de 1 GiB llamado
1GiB.txt, concatena 32 copias de32MiB.txt:Para compilar objetos de prueba de potencia de dos a partir de
1GiB.txt(2GiB.txt,4GiB.txt,8GiB.txt,16GiB.txty32GiB.txt), repite la operación de composición:
Coordina las descargas de bandas simultáneas
Para descargar un objeto en paralelo, consulta su tamaño y generación,
asigna previamente el archivo de destino local y genera un futuro por segmento. Dentro de una función download que acepte client, control, bucket_name, object_name, stripe_size y destination, completa los siguientes pasos:
Recupera los metadatos del objeto con
StorageControl::get_objectpara que puedas inspeccionar el tamaño total del objeto y bloquear las lecturas posteriores en una sola generación:Crea el archivo de destino y asígnalo previamente al tamaño exacto del objeto para que las tareas de los trabajadores puedan escribir en compensaciones de bytes independientes:
Calcula cada desplazamiento de banda con
stripe_sizecomolimity crea un futurowrite_stripepor segmento, agregando una banda parcial final cuando el tamaño del objeto no sea divisible de manera uniforme porlimit:Ejecuta todos los futuros de Stripe de forma simultánea con
futures::future::join_ally propaga los errores:
Descarga y escribe una banda individual
Cada tarea de write_stripe lee un solo rango de bytes de Cloud Storage
y escribe los fragmentos recibidos en el desplazamiento correspondiente en el manejo de archivos local
compartido. Para implementar write_stripe, completa los siguientes pasos:
Importa
ReadRangey define la funciónwrite_stripe:Crea un compilador de solicitudes
ReadObjectconStorage::read_objecty envía la solicitud después de configurar las opciones de generación y rango de lectura en los siguientes pasos:Para fijar todas las bandas a la misma generación de objetos y evitar lecturas incoherentes si otro proceso reemplaza el objeto, llama a
set_generationen el compilador de solicitudes antes de llamar asend:Para restringir la lectura al rango de bytes de la banda, llama a
set_read_rangeconReadRange::segment(offset, limit)en el compilador de solicitudes:Transmite fragmentos desde el lector y escribe cada fragmento en el archivo de destino en
current_posdentro detokio::task::spawn_blocking. Debido a que la biblioteca estándar de Rust carece de un método de escritura posicional multiplataforma, en este ejemplo se usaFileExt::write_all_aten Unix yFileExt::seek_writeen Windows:
Consideraciones de rendimiento
Varios factores determinan la capacidad de procesamiento efectiva de las descargas divididas:
- Velocidad del disco local. Escribir fragmentos en un almacenamiento local lento puede convertirse en el cuello de botella. El uso de almacenamiento en SSD locales de alta capacidad de procesamiento ayuda a mantener la E/S de disco por delante de las lecturas de red.
- Capacidad de CPU de la VM. Cloud Storage encripta los datos de los objetos en tránsito, por lo que el cliente desencripta cada fragmento que recibe. Asegúrate de que tu VM tenga suficientes vCPUs para controlar el desencriptado de TLS simultáneo en las bandas.
- Ubicación del bucket y de la VM. La descarga entre regiones genera latencia de red de área extensa y limita la capacidad de procesamiento. Coloca tu VM en la misma región que tu bucket cuando sea posible.
También puedes experimentar con el ajuste de stripe_size para evitar dejar una franja
restante muy pequeña o crear demasiadas solicitudes de rango pequeñas.
Completar código
En el siguiente ejemplo, se combinan las funciones seed, download y write_stripe
en un módulo completo:
Cuando ejecutas download en un objeto de 32 MiB con un stripe_size de 1 MiB,
el resultado es similar al siguiente, en el que se informa el tamaño descargado, el tiempo transcurrido,
el recuento de bandas y el ancho de banda efectivo:
Completed 32.00 MiB download in 412.5ms, using 32 stripes, effective bandwidth = 77.58 MiB/s
Realiza una limpieza
Para evitar que se apliquen cargos a tu cuenta de Google Cloud por los objetos de prueba
creados por seed, borra los objetos de prueba y
borra el bucket de prueba cuando termines. También quita el
archivo de destino local.