Como escrever scripts em transferências de produção

Visão geral

Se você usa o gsutil em grandes tarefas de produção (como upload ou download de muitos GiBs de dados todas as noites), há muita coisa que pode ser feita garantir o sucesso. Esta seção discute especificamente como criar scripts de grandes tarefas de produção com o mecanismo de transferência recuperável do gsutil.

Contexto sobre as transferências recuperáveis

Primeiro, é útil entender o mecanismo de transferência recuperável do gsutil e como o script precisa ser implementado nesse mecanismo para funcionar de maneira confiável. O gsutil usa o suporte à transferência recuperável ao tentar fazer o download de um arquivo de qualquer tamanho ou fazer o upload de um arquivo maior que um limite configurável (por padrão, esse limite é 8 MiB). Se uma transferência falhar no meio (por exemplo, devido a um problema de rede intermitente), o gsutil usará uma estratégia truncada aleatória de retirada e repetição binária que, por padrão, tentará fazê-la novamente até 23 vezes em um período de 10 minutos (veja detalhes em gsutil help retries). Se a transferência falhar em cada uma dessas tentativas sem um progresso intermediário, o gsutil desistirá da transferência, mas manterá um arquivo "rastreador" para ela em um local configurável. O local padrão é ~/.gsutil/, em um arquivo com nome baseado em uma combinação do hash SHA1 do nome do bucket e do objeto que está sendo transferido e dos últimos 16 caracteres do nome do arquivo. Quando uma transferência falha dessa forma, é possível executar novamente o gsutil depois (por exemplo, após o problema de rede ter sido resolvido), e a transferência recuperável recomeça de onde parou.

Como criar scripts de tarefas de transferência de dados

Para criar um script de tarefas de transferência de dados de produção de grande porte nesse mecanismo, implemente um script que seja executado periodicamente, determine quais transferências de arquivos ainda não foram concluídas e execute o gsutil para copiá-los. Veja algumas sugestões sobre como esse tipo de script deve ser implementado:

  1. Quando as transferências recuperáveis falham sem progresso 23 vezes seguidas por um período de até 10 minutos, é provável que não basta tentar a transferência de novo imediatamente. Uma estratégia mais bem-sucedida seria ter um cron job sendo executado a cada 30 minutos, determinando quais transferências precisam ser executadas e executando-as. Se a rede enfrentar problemas intermitentes, o script continuará de onde parou e finalmente terá êxito (depois que o problema de rede tiver sido resolvido).

  2. Se seu negócio depende de transferências de dados em tempo hábil, considere a implementação de um monitoramento de rede. Por exemplo, é possível implementar uma tarefa que tenta fazer um pequeno download em intervalos de alguns minutos e emite um alerta se a tentativa falhar várias vezes seguidas (ou mais ou menos frequentemente, conforme os requisitos), para que a equipe de TI possa investigar os problemas de imediato. Como é praxe nas implementações de monitoramento, faça testes com os limites de alerta, para evitar alertas com falso positivo que fazem com que sua equipe comece a ignorá-los.

  3. Há várias maneiras de determinar quais arquivos ainda precisam ser transferidos. Evite a tentativa de conseguir uma listagem completa de um bucket que contém muitos objetos (por exemplo, dezenas de milhares ou mais). Uma estratégia é estruturar os nomes de objeto de uma forma que represente o processo de transferência e também usar caracteres curinga de prefixo do gsutil para solicitar listagens parciais do bucket. Por exemplo, se o processo periódico envolve o download dos objetos do dia atual, é possível pode nomear objetos usando um formato ano-mês-dia-objeto-ID e, em seguida, encontrar os objetos de hoje usando um comando como gsutil ls "gs://bucket/2011-09-27-*". É mais eficiente ter um prefixo sem caractere curinga do que usar algo como gsutil ls "gs://bucket/*-2011-09-27". Na verdade, o último comando solicita uma listagem completa do bucket e filtra no gsutil, enquanto o primeiro solicita que o Google Storage retorne o subconjunto de objetos cujos nomes começam com tudo que há antes do "*".

    Para uploads de dados, outra técnica seria mover arquivos locais de uma área "a ser processado" para uma área "concluído" à medida que o script copia os arquivos para a nuvem com sucesso. É possível fazer isso em lotes paralelos usando um comando como:

    gsutil -m cp -r to_upload/subdir_$i gs://bucket/subdir_$i
    

    em que i é uma variável de loop do shell. Verifique se a variável $status do shell é 0 depois de cada comando gsutil cp para detectar se algumas das cópias falharam e execute novamente as cópias afetadas.

    Com essa estratégia, o sistema de arquivos monitora o trabalho que ainda precisa ser feito.

  4. Se você tiver uma grande quantidade de objetos em um único bucket (por exemplo, centenas de milhares ou mais), considere rastrear os objetos em um banco de dados em vez de usar as listagens de bucket para enumerá-los. Por exemplo, esse banco de dados pode rastrear o estado dos downloads. Assim, é possível determinar quais objetos precisam ser transferidos pelo script de download periódico consultando o banco de dados localmente, e não executando uma listagem do bucket.

  5. Não exclua arquivos temporários transferidos por download parcialmente após uma falha na transferência: o gsutil continua de onde parou e executa um hash do conteúdo final transferido para garantir a integridade dos dados. Portanto, excluir os arquivos transferidos parcialmente fará com que você perca o progresso e use mais a rede de modo desnecessário.

  6. Se você tiver uma conexão de rede rápida, poderá acelerar a transferência de muitos arquivos usando a opção gsutil -m (multissegmentação/ multiprocessamento). No entanto, o gsutil não tenta rastrear quais arquivos foram transferidos com sucesso nos casos em que alguns arquivos apresentaram falha de download. Por exemplo, se você usar transferências multissegmentadas para fazer o download de 100 arquivos e três apresentarem falha, caberá ao processo do script determinar quais transferências não tiveram êxito e tentá-las novamente. Uma abordagem periódica de verificação e execução, como a descrita anteriormente, resolveria esse caso.

    Se você usa transferências paralelas (gsutil -m), pode fazer testes com o número de linhas de execução que estão sendo usadas (por meio da configuração parallel_thread_count no arquivo de configuração .boto). Por padrão, o gsutil usa 10 linhas de execução no Linux e 24 linhas de execução em outros sistemas operacionais. Conforme a velocidade da rede, a memória disponível, a carga da CPU e outras condições, isso pode ou não ser a melhor opção. Faça testes com quantidades maiores ou menores de linhas de execução para encontrar o melhor número de linhas para seu ambiente.