O download sequencial de um objeto grande no Cloud Storage em uma única conexão pode deixar a largura de banda de rede disponível sem uso. Ao dividir um objeto em segmentos de intervalo de bytes chamados de faixas e ler esses segmentos simultaneamente, é possível melhorar a capacidade de download de objetos grandes usando as bibliotecas de cliente do Cloud para Rust.
Neste documento, mostramos como propagar objetos de teste grandes usando a
composição de objetos, fazer o download de intervalos de bytes simultaneamente com
ReadRange::segment e gravar faixas em um arquivo local em deslocamentos fixos. Se
você não conhece a biblioteca de cliente, consulte
Como usar o Cloud Storage com Rust primeiro.
Antes de começar
Antes de executar o código neste documento, conclua os seguintes pré-requisitos:
- Crie ou selecione um projeto doGoogle Cloud com o faturamento ativado.
- Crie um bucket do Cloud Storage dedicado de teste no seu projeto.
- Configure o Application Default Credentials para seu ambiente.
- Conceda ao principal um papel do Identity and Access Management (IAM) com permissão para
ler, gravar, compor e excluir objetos no bucket, como Administrador do Storage
(
roles/storage.admin).
Dependências
Adicione a biblioteca de cliente do Cloud Storage e os crates de suporte ao arquivo
Cargo.toml:
cargo add google-cloud-storage google-cloud-gax anyhow bytes futures
cargo add tokio --features macros,rt-multi-thread
Criar objetos de teste grandes
Para testar downloads distribuídos sem fazer upload de gigabytes de dados pela rede, faça upload de um pequeno objeto de semente e use a operação de composição do Cloud Storage para concatenar cópias do lado do servidor. Em uma
função assíncrona seed que aceita client, control e bucket_name
no formato projects/_/buckets/BUCKET_ID, siga estas
etapas:
Para referenciar objetos em solicitações de composição, importe
SourceObject:Faça upload de um objeto de sugestão de 1 MiB chamado
1MiB.txt:Para criar um objeto de 32 MiB chamado
32MiB.txt, concatene 32 cópias de1MiB.txtno servidor:Para criar um objeto de 1 GiB chamado
1GiB.txt, concatene 32 cópias de32MiB.txt:Para criar objetos de teste de potência de dois de
1GiB.txt(2GiB.txt,4GiB.txt,8GiB.txt,16GiB.txte32GiB.txt), repita a operação de composição:
Coordenar downloads simultâneos de faixas
Para fazer o download de um objeto em paralelo, consulte o tamanho e a geração dele,
pré-aloque o arquivo de destino local e gere um futuro por faixa. Em
uma função download que aceita client, control, bucket_name,
object_name, stripe_size e destination, siga estas etapas:
Busque os metadados do objeto usando
StorageControl::get_objectpara inspecionar o tamanho total do objeto e bloquear as leituras subsequentes em uma única geração:Crie o arquivo de destino e pré-aloque-o para o tamanho exato do objeto para que as tarefas de worker possam gravar em deslocamentos de bytes independentes:
Calcule cada deslocamento de faixa usando
stripe_sizecomolimite crie um futurowrite_stripepor segmento, adicionando uma faixa parcial final quando o tamanho do objeto não for divisível porlimit:Execute todos os futuros de stripe simultaneamente com
futures::future::join_alle propague os erros:
Fazer o download e gravar uma faixa individual
Cada tarefa write_stripe lê um único intervalo de bytes do Cloud Storage
e grava os blocos recebidos no deslocamento correspondente no identificador de processamento de arquivos local
compartilhado. Para implementar write_stripe, siga estas etapas:
Importe
ReadRangee defina a funçãowrite_stripe:Crie um builder de solicitações
ReadObjectcomStorage::read_objecte envie a solicitação depois de configurar as opções de geração e intervalo de leitura nas etapas a seguir:Para fixar todas as listras na mesma geração de objeto e evitar leituras inconsistentes se outro processo substituir o objeto, chame
set_generationno criador de solicitações antes de chamarsend:Para restringir a leitura ao intervalo de bytes da faixa, chame
set_read_rangecomReadRange::segment(offset, limit)no builder de solicitações:Transmita blocos do leitor e grave cada bloco no arquivo de destino em
current_posdentro detokio::task::spawn_blocking. Como a biblioteca padrão do Rust não tem um método de gravação posicional multiplataforma, este exemplo usaFileExt::write_all_atno Unix eFileExt::seek_writeno Windows:
Considerações sobre desempenho
Vários fatores determinam a capacidade de processamento efetiva de downloads distribuídos:
- Velocidade do disco local. A gravação de blocos em um armazenamento local lento pode se tornar o gargalo. O uso do armazenamento SSD local de alta capacidade de processamento ajuda a manter a E/S de disco à frente das leituras de rede.
- Capacidade de CPU da VM. O Cloud Storage criptografa os dados do objeto em trânsito, então o cliente descriptografa cada bloco recebido. Verifique se a VM tem vCPUs suficientes para lidar com a descriptografia simultânea de TLS em todas as faixas.
- Local do bucket e da VM. O download entre regiões introduz latência de rede de longa distância e limita a capacidade de processamento. Coloque a VM na mesma região do bucket, quando possível.
Você também pode ajustar stripe_size para evitar deixar uma faixa restante muito pequena ou criar muitas solicitações de intervalo pequenas.
Preencher código
O exemplo a seguir combina as funções seed, download e write_stripe
em um módulo completo:
Quando você executa download em um objeto de 32 MiB com um stripe_size de 1 MiB,
a saída é semelhante à seguinte, informando o tamanho do download, o tempo decorrido,
a contagem de listras e a largura de banda efetiva:
Completed 32.00 MiB download in 412.5ms, using 32 stripes, effective bandwidth = 77.58 MiB/s
Limpar
Para evitar cobranças na sua conta do Google Cloud pelos objetos de teste criados pelo seed, exclua os objetos de teste e exclua o bucket de teste quando terminar. Remova também o
arquivo de destino local.