Práticas recomendadas da API BigQuery Storage Write

Neste documento, você conhecerá as práticas recomendadas para usar a API BigQuery Storage Write. Antes de ler este documento, leia Visão geral da API de gravação do BigQuery Storage.

Restrinja a taxa de criação de stream

Antes de criar um fluxo, considere se é possível usar o stream padrão. Para cenários de streaming, o stream padrão tem menos limitações de cota e pode escalonar melhor do que usar streams criados por aplicativos. Se você usar um fluxo criado por aplicativo, use a capacidade máxima em cada fluxo antes de criar outros streams. Por exemplo, use gravações assíncronas.

Para streams criados pelo aplicativo, evite chamar CreateWriteStream em uma frequência alta. Geralmente, se você exceder de 40 a 50 chamadas por segundo, a latência das chamadas de API aumentará substancialmente (mais de 25 segundos). Verifique se o aplicativo pode aceitar uma inicialização a frio e aumentar gradualmente o número de streams e limitar a taxa de chamadas CreateWriteStream. Também é possível definir um prazo maior para aguardar a conclusão da chamada, para que ela não falhe com um erro DeadlineExceeded. Há também uma cota de longo prazo na taxa máxima de chamadas CreateWriteStream. A criação de streams é um processo que usa muitos recursos. Portanto, reduzir a taxa de criação de streams e usar os streams atuais é a melhor maneira de não ultrapassar esse limite.

Gerenciamento do pool de conexões

O método AppendRows cria uma conexão bidirecional com um stream. É possível abrir várias conexões no stream padrão, mas apenas uma conexão ativa em streams criados por aplicativo.

Ao usar o stream padrão, é possível usar a multiplexação da API Storage Write para gravar em várias tabelas de destino com conexões compartilhadas. Multiplexação de conexões de pools para melhor capacidade e utilização de recursos. Caso seu fluxo de trabalho tenha mais de 20 conexões simultâneas, recomendamos que você use multiplexação. A multiplexação está disponível em Java e Go. Para mais detalhes de implementação em Java, consulte Usar multiplexação. Para detalhes de implementação do Go, consulte Compartilhamento de conexão (multiplexação). Se você usa o conector do Beam com semântica do menos uma vez, é possível ativar a multiplexação com UseStorageApiConnectionPool. O conector Spark do Dataproc tem a multiplexação ativada por padrão.

Para ter o melhor desempenho, use uma conexão para o máximo possível de gravações de dados. Não use uma conexão para apenas uma única gravação, ou fluxos abertos e fechados para muitas gravações pequenas.

Há uma cota para o número de conexões simultâneas que podem ser abertas ao mesmo tempo por projeto. Acima do limite, as chamadas para AppendRows falham. No entanto, a cota de conexões simultâneas pode ser aumentada e não costuma ser um fator limitante do escalonamento.

Cada chamada para AppendRows cria um novo objeto de gravação de dados. Portanto, ao usar um stream criado pelo aplicativo, o número de conexões corresponde ao número de streams que foram criados. Geralmente, uma única conexão é compatível com pelo menos 1 MBps de capacidade de processamento. O limite superior depende de vários fatores, como a largura de banda da rede, o esquema dos dados e a carga do servidor, mas pode exceder 10MBps.

Há também uma cota da capacidade de processamento total por projeto. Ela representa os bytes por segundo em todas as conexões que fluem pelo serviço da API Storage Write. Se o projeto exceder essa cota, solicite um limite de cota maior. Normalmente, isso envolve o aumento das cotas associadas, como a cota de conexões simultâneas, em uma proporção igual.

Gerencie os deslocamentos de stream para alcançar uma semântica exatamente uma vez

A API StorageWrite só permite gravações no final do fluxo, que se move à medida que os dados são anexados. A posição atual no stream é especificada como um deslocamento desde o início do stream.

Ao gravar em um fluxo criado por aplicativo, é possível especificar o deslocamento de stream para alcançar a semântica de gravação exatamente uma vez.

Quando você especifica um deslocamento, a operação de gravação é idempotente, o que torna seguro tentar novamente devido a erros de rede ou não resposta do servidor. Solucionar os seguintes erros relacionados a deslocamentos:

  • ALREADY_EXISTS (StorageErrorCode.OFFSET_ALREADY_EXISTS): a linha já foi gravada. Você pode ignorar esse erro com segurança.
  • OUT_OF_RANGE (StorageErrorCode.OFFSET_OUT_OF_RANGE): uma operação de gravação anterior falhou. Tentar novamente a partir da última gravação bem-sucedida.

Esses erros também podem acontecer se você definir o valor de deslocamento incorreto. Portanto, será necessário gerenciar os deslocamentos com cuidado.

Antes de usar deslocamentos de stream, considere se você precisa de uma semântica exatamente uma vez. Por exemplo, se o pipeline de dados upstream garantir apenas gravações do tipo "pelo menos uma vez" ou se for possível detectar com facilidade cópias após a ingestão de dados, talvez você não precise de gravações exatamente uma vez. Nesse caso, recomendamos usar o fluxo padrão, que não exige o controle dos deslocamentos de linha.

Não bloqueie nas chamadas para AppendRows

O método AppendRows é assíncrono. É possível enviar uma série de gravações sem bloquear uma resposta para cada gravação individualmente. As mensagens de resposta na conexão bidirecional chegam na mesma ordem em que as solicitações foram enfileiradas. Para ter a maior capacidade de processamento, chame AppendRows sem bloqueio para aguardar a resposta.

Gerenciar atualizações de esquemas

Em cenários de streaming de dados, os esquemas de tabela geralmente são gerenciados fora do pipeline de streaming. É comum que o esquema evolua com o passar do tempo, por exemplo, com a adição de novos campos anuláveis. Um pipeline robusto precisa processar atualizações de esquema fora de banda.

A API StorageWrite é compatível com esquemas de tabelas da seguinte maneira:

  • A primeira solicitação de gravação inclui o esquema.
  • Você envia cada linha de dados como um buffer de protocolo binário. O BigQuery mapeia os dados para o esquema.
  • É possível omitir campos anuláveis, mas não é possível incluir campos que não estejam presentes no esquema atual. Se você enviar linhas com campos extras, a API StorageWrite retornará um StorageError com StorageErrorCode.SCHEMA_MISMATCH_EXTRA_FIELD.

Se você quiser enviar novos campos no payload, primeiro atualize o esquema da tabela no BigQuery. A API StorageWrite detecta alterações de esquema após um curto período, em ordem de minutos. Quando a API Storage Record detecta a mudança de esquema, a mensagem de resposta AppendRowsResponse contém um objeto TableSchema que descreve o novo esquema.

Para enviar dados usando o esquema atualizado, feche as conexões atuais e abra novas conexões com o novo esquema.

Cliente Java. A biblioteca de cliente Java oferece alguns outros recursos para atualizações de esquema com a classe JsonStreamWriter. Após uma atualização de esquema, o JsonStreamWriter se reconecta automaticamente com o esquema atualizado. Não é necessário fechar e reabrir a conexão explicitamente. Para verificar se as mudanças de esquema são programáticas, chame AppendRowsResponse.hasUpdatedSchema após a conclusão do método append.

Você também pode configurar JsonStreamWriter para ignorar campos desconhecidos nos dados de entrada. Para definir esse comportamento, chame setIgnoreUnknownFields. Esse comportamento é semelhante à opção ignoreUnknownValues ao usar a API tabledata.insertAll legada. No entanto, isso pode levar à perda não intencional de dados, porque os campos desconhecidos são descartados silenciosamente.