Il download sequenziale di un oggetto di grandi dimensioni in Cloud Storage su una singola connessione può lasciare inutilizzata la larghezza di banda di rete disponibile. Dividendo un oggetto in segmenti di intervalli di byte chiamati stripe e leggendo questi segmenti contemporaneamente, puoi migliorare la velocità effettiva di download per oggetti di grandi dimensioni utilizzando le librerie client di Cloud per Rust.
Questo documento mostra come eseguire il seeding di oggetti di test di grandi dimensioni utilizzando la composizione degli oggetti, scaricare intervalli di byte contemporaneamente con ReadRange::segment e scrivere stripe in un file locale con offset fissi. Se non hai mai utilizzato la libreria client, consulta prima Utilizzo di Cloud Storage con Rust.
Prima di iniziare
Prima di eseguire il codice in questo documento, completa i seguenti prerequisiti:
- Crea o seleziona un progettoGoogle Cloud con la fatturazione abilitata.
- Crea un bucket Cloud Storage di test dedicato nel tuo progetto.
- Configura le Credenziali predefinite dell'applicazione per il tuo ambiente.
- Concedi alla tua entità un ruolo Identity and Access Management (IAM) con l'autorizzazione per leggere, scrivere, comporre ed eliminare oggetti nel bucket, ad esempio Storage Admin (
roles/storage.admin).
Dipendenze
Aggiungi la libreria client di Cloud Storage e i crate di supporto al file Cargo.toml:
cargo add google-cloud-storage google-cloud-gax anyhow bytes futures
cargo add tokio --features macros,rt-multi-thread
Crea oggetti di test di grandi dimensioni
Per testare i download in parallelo senza caricare gigabyte di dati sulla rete, carica un piccolo oggetto seed e utilizza l'operazione di composizione di Cloud Storage per concatenare le copie lato server. All'interno di una funzione seed asincrona che accetta client, control e bucket_name nel formato projects/_/buckets/BUCKET_ID, completa i seguenti passaggi:
Per fare riferimento a oggetti esistenti nelle richieste di composizione, importa
SourceObject:Carica un oggetto seed da 1 MiB denominato
1MiB.txt:Per creare un oggetto da 32 MiB denominato
32MiB.txt, concatena 32 copie di1MiB.txtsul server:Per creare un oggetto da 1 GiB denominato
1GiB.txt, concatena 32 copie di32MiB.txt:Per creare oggetti di test con dimensioni pari a una potenza di due da
1GiB.txt(2GiB.txt,4GiB.txt,8GiB.txt,16GiB.txte32GiB.txt), ripeti l'operazione di composizione:
Coordinare i download simultanei di stripe
Per scaricare un oggetto in parallelo, esegui una query sulle sue dimensioni e sulla sua generazione, prealloca il file di destinazione locale e genera un future per stripe. All'interno di una funzione download che accetta client, control, bucket_name, object_name, stripe_size e destination, completa i seguenti passaggi:
Recupera i metadati dell'oggetto utilizzando
StorageControl::get_objectin modo da poter esaminare le dimensioni totali dell'oggetto e bloccare le letture successive a una singola generazione:Crea il file di destinazione e preassegnalo alle dimensioni esatte dell'oggetto in modo che le attività dei worker possano scrivere in offset di byte indipendenti:
Calcola l'offset di ogni stripe utilizzando
stripe_sizecomelimite crea unwrite_stripefuture per segmento, aggiungendo uno stripe parziale finale quando la dimensione dell'oggetto non è divisibile in modo uniforme perlimit:Esegui tutti i future di stripe contemporaneamente con
futures::future::join_alle propaga eventuali errori:
Scarica e scrivi una singola striscia
Ogni attività write_stripe legge un singolo intervallo di byte da Cloud Storage e scrive i blocchi ricevuti nell'offset corrispondente nell'handle di gestione di file locale condiviso. Per implementare write_stripe, completa i seguenti passaggi:
Importa
ReadRangee definisci la funzionewrite_stripe:Crea un generatore di richieste
ReadObjectconStorage::read_objecte invia la richiesta dopo aver configurato le opzioni di generazione e intervallo di lettura nei seguenti passaggi:Per bloccare tutti gli stripe alla stessa generazione di oggetti ed evitare letture incoerenti se un altro processo sovrascrive l'oggetto, chiama
set_generationsul generatore di richieste prima di chiamaresend:Per limitare la lettura all'intervallo di byte dello stripe, chiama
set_read_rangeconReadRange::segment(offset, limit)sul generatore di richieste:Trasmetti in streaming i blocchi dal lettore e scrivi ogni blocco nel file di destinazione in
current_posall'interno ditokio::task::spawn_blocking. Poiché la libreria standard di Rust non dispone di un metodo di scrittura posizionale multipiattaforma, questo esempio utilizzaFileExt::write_all_atsu Unix eFileExt::seek_writesu Windows:
Considerazioni sulle prestazioni
Diversi fattori determinano il throughput effettivo dei download con striping:
- Velocità del disco locale. La scrittura di blocchi in uno spazio di archiviazione locale lento può diventare il collo di bottiglia. L'utilizzo di uno spazio di archiviazione SSD locale con throughput elevato aiuta a mantenere l'I/O del disco in vantaggio rispetto alle letture di rete.
- Capacità della CPU della VM. Cloud Storage cripta i dati degli oggetti in transito, quindi il client decripta ogni blocco che riceve. Assicurati che la VM disponga di vCPU sufficienti per gestire la decrittografia TLS simultanea tra gli stripe.
- Posizione del bucket e della VM. Il download tra regioni introduce la latenza della wide area network e limita la velocità effettiva. Se possibile, colloca la VM nella stessa regione del bucket.
Puoi anche sperimentare con l'ottimizzazione di stripe_size per evitare di lasciare una striscia rimanente molto piccola o di creare troppe richieste di intervallo di piccole dimensioni.
Completamento codice
L'esempio seguente combina le funzioni seed, download e write_stripe in un modulo completo:
Quando esegui download su un oggetto da 32 MiB con un stripe_size da 1 MiB, l'output è simile al seguente e riporta le dimensioni del download, il tempo trascorso, il numero di stripe e la larghezza di banda effettiva:
Completed 32.00 MiB download in 412.5ms, using 32 stripes, effective bandwidth = 77.58 MiB/s
Esegui la pulizia
Per evitare che al tuo account Google Cloud vengano addebitati costi per gli oggetti di test creati da seed, elimina gli oggetti di test ed elimina il bucket di test al termine. Rimuovi anche il file di destinazione locale.