Práticas recomendadas de ajuste de performance

Este documento oferece orientações sobre como melhorar o Cloud Storage FUSE usando os principais recursos e configurações do Cloud Storage FUSE para alcançar a capacidade máxima e o desempenho ideal, especialmente para cargas de trabalho de inteligência artificial e machine learning (IA/ML), como treinamento, disponibilização e checkpointing.

Considerações

Antes de aplicar as configurações recomendadas nesta página, considere o seguinte:

  • É possível aplicar as configurações recomendadas nesta página usando os seguintes métodos:

  • Verifique se você está executando a versão mais recente do Cloud Storage FUSE. As configurações recomendadas só devem ser aplicadas ao Cloud Storage FUSE versão 3.0 ou posterior e ao driver CSI do Cloud Storage FUSE para Google Kubernetes Engine que é executado em clusters do GKE versão 1.32.2-gke.1297001 ou posterior.

  • As configurações recomendadas armazenam em cache os metadados do Cloud Storage durante o job e não são verificadas após a montagem inicial do sistema de arquivos. Portanto, recomendamos que o sistema de arquivos seja somente leitura ou que a semântica do sistema de arquivos seja de aplicativos gravar em novo, ou seja, aplicativos que sempre gravam em novos arquivos, para um desempenho ideal. As seguintes cargas de trabalho de IA/ML são de gravação em novo:

  • As configurações recomendadas nesta página foram validadas para GPUs do Cloud e tipos de máquinas grandes do Cloud TPU em grande escala, com uma grande quantidade de memória e uma interface de rede de alta largura de banda. Os tipos de máquina das Cloud GPUs e da Cloud TPU podem variar em termos de número de recursos disponíveis, como CPU, memória e armazenamento local na configuração do nó host. Isso pode afetar diretamente o desempenho de configurações como as seguintes:

Suporte ao Rapid Bucket

A partir da versão 3.7.1, o Cloud Storage FUSE oferece suporte ao Rapid Bucket com caminho de leitura otimizado.

O caminho de leitura otimizado melhora significativamente o desempenho usando o algoritmo de leitura antecipada do kernel do Linux por padrão. Para usar esse caminho de leitura otimizado, são necessárias mudanças específicas na configuração no nível da máquina para os parâmetros read_ahead_kb, max_background e congestion_threshold. Em ambientes do Google Kubernetes Engine (GKE) que usam o driver CSI do Cloud Storage FUSE, essas configurações são totalmente gerenciadas e aplicadas automaticamente. Para VMs do Compute Engine e outros ambientes que não são do GKE, o Cloud Storage FUSE exige permissões sudo para aplicar essas alterações automaticamente. Caso contrário, é necessário configurar esses parâmetros manualmente.

Ao usar o caminho de leitura otimizado para o Rapid Bucket, lembre-se dos seguintes comportamentos e limitações:

  • Compatibilidade com cache de arquivos e leitor em buffer:como o caminho de leitura otimizado depende do algoritmo de leitura antecipada do kernel, ele é incompatível com o cache de arquivos e o leitor em buffer do Cloud Storage FUSE. Por padrão, esses recursos ficam inativos (sem operação) para o Rapid Bucket. Se a carga de trabalho exigir o cache de arquivos ou o leitor em buffer, desative explicitamente o leitor de kernel definindo enable-kernel-reader: false durante a montagem. Isso fará com que o Cloud Storage FUSE use o caminho de leitura padrão, que é compatível com o armazenamento em cache de arquivos e leituras em buffer.
  • Requisitos de montagem:o novo caminho de leitura é compatível apenas com montagens estáticas. Não é compatível com a montagem dinâmica.

Usar buckets com namespace hierárquico ativado

Sempre use buckets com o namespace hierárquico ativado. O namespace hierárquico organiza os dados em uma estrutura hierárquica de sistema de arquivos, o que torna as operações no bucket mais eficientes, resultando em tempos de resposta mais rápidos e menos chamadas de lista em geral para cada operação.

Os benefícios do namespace hierárquico incluem:

  • Os buckets com namespace hierárquico oferecem até oito vezes mais consultas por segundo (QPS) iniciais em comparação com os buckets simples. O namespace hierárquico oferece suporte a 40.000 solicitações iniciais de leitura de objetos por segundo e 8.000 solicitações iniciais de gravação de objetos, o que é significativamente maior do que os buckets simples típicos do Cloud Storage FUSE, que oferecem apenas 5.000 solicitações iniciais de leitura de objetos por segundo e 1.000 solicitações iniciais de gravação de objetos.

  • O namespace hierárquico fornece renomeações atômicas de diretório, que são necessárias para a criação de checkpoints com o Cloud Storage FUSE para garantir a atomicidade. O uso de buckets com namespace hierárquico ativado é especialmente benéfico ao criar checkpoints em grande escala, porque os frameworks de ML usam renomeações de diretório para finalizar checkpoints, que é um comando rápido e atômico, e só é compatível com buckets com namespace hierárquico ativado. Se você optar por não usar um bucket com namespace hierárquico ativado, consulte Aumentar o limite de renomeação para buckets sem HNS.

Para saber como criar um bucket com o namespace hierárquico ativado, consulte Criar buckets com o namespace hierárquico ativado. Para saber como montar um bucket com namespace hierárquico ativado, consulte Montar buckets com namespace hierárquico ativado. O namespace hierárquico é compatível com as versões 1.31.1-gke.2008000 ou mais recentes do Google Kubernetes Engine.

Realizar uma montagem específica do diretório

Se você quiser acessar um diretório específico em um bucket, use a opção de montagem only-dir para montar apenas esse diretório, em vez de montar todo o bucket. A montagem específica de diretório acelera as chamadas de lista e reduz o número geral de chamadas de lista e estatísticas, limitando o número de diretórios a serem percorridos ao resolver um nome de arquivo, porque as chamadas LookUpInode e as solicitações de acesso a buckets ou diretórios geram automaticamente chamadas de lista e estatísticas para cada arquivo ou diretório no caminho.

Para montar um diretório específico, use um dos seguintes métodos:

Google Kubernetes Engine

Para volumes permanentes, use a seguinte configuração de montagem com o driver CSI do Cloud Storage FUSE para Google Kubernetes Engine:

mountOptions:
    - only-dir:DIRECTORY_NAME

Para volumes temporários, adicione a configuração de montagem ao volumeAttributes.mountOptions, com flags separadas por vírgulas:

mountOptions: "OTHER_OPTIONS,only-dir:DIRECTORY_NAME"

Substitua DIRECTORY_NAME pelo nome do diretório que você quer montar.

Compute Engine

Execute o comando gcsfuse --only-dir para montar um diretório específico em uma máquina virtual do Compute Engine:

gcsfuse --only-dir DIRECTORY_NAME BUCKET_NAME MOUNT_POINT

Substitua:

  • BUCKET_NAME é o nome do bucket em que você quer montar o diretório.

  • DIRECTORY_NAME é o nome do diretório que você quer ativar.

  • MOUNT_POINT é o diretório local em que o bucket será ativado. Por exemplo, /path/to/mount/point.

Para mais informações sobre como fazer uma ativação de diretório, consulte Ativar um diretório em um bucket.

Aumentar os valores de cache de metadados

Para melhorar o desempenho de leituras repetidas, configure o Cloud Storage FUSE para armazenar em cache uma grande quantidade de metadados e ignorar a expiração de metadados, o que evita solicitações repetidas de metadados para o Cloud Storage e melhora significativamente o desempenho.

Aumentar os valores do cache de metadados é útil para cargas de trabalho com leituras repetidas, para evitar chamadas repetitivas do Cloud Storage e para volumes somente leitura em que um TTL infinito pode ser definido.

Considere o seguinte antes de aumentar os valores do cache de metadados:

  • Um time to live (TTL) infinito só deve ser definido para volumes que são somente leitura ou somente gravação em novos.

  • O cache de metadados só deve ser ativado para aumentar significativamente de tamanho em nós com configurações de memória grandes, porque ele armazena em cache todos os metadados do ponto de montagem especificado em cada nó e elimina a necessidade de acesso adicional ao Cloud Storage.

  • As configurações nesta seção armazenam em cache todos os metadados acessados com um TTL infinito, o que pode afetar as garantias de consistência quando alterações são feitas no mesmo bucket do Cloud Storage por qualquer outro cliente, por exemplo, substituições ou exclusões de um arquivo.

  • Para verificar se o consumo de memória não é afetado, confirme se a quantidade de memória consumida pelo cache de metadados é aceitável para você, o que pode aumentar para gigabytes e depende do número de arquivos nos buckets montados e de quantos pontos de montagem estão sendo usados. Por exemplo, os metadados de cada arquivo ocupam cerca de 1,5 KiB de memória e, de forma relativa, os metadados de um milhão de arquivos ocupam aproximadamente 1,5 GiB de memória. Para mais informações, consulte Visão geral do armazenamento em cache.

Siga estas instruções para configurar o Cloud Storage FUSE e armazenar em cache uma grande quantidade de metadados e ignorar o vencimento deles:

Opções de gcsfuse

gcsfuse --metadata-cache-ttl-secs=-1 \
      --stat-cache-max-size-mb=-1 \
      BUCKET_NAME MOUNT_POINT

Substitua:

  • BUCKET_NAME é o nome do bucket.

  • MOUNT_POINT é o diretório local em que o bucket será ativado. Por exemplo, /path/to/mount/point.

Arquivo de configuração

metadata-cache:
stat-cache-max-size-mb: -1
ttl-secs: -1

Google Kubernetes Engine

  mountOptions:
      - metadata-cache:ttl-secs:-1
      - metadata-cache:stat-cache-max-size-mb:-1

Compute Engine

gcsfuse --metadata-cache-ttl-secs=-1 \
      --stat-cache-max-size-mb=-1 \
      BUCKET_NAME MOUNT_POINT

Substitua:

  • BUCKET_NAME é o nome do bucket.

  • MOUNT_POINT é o diretório local em que o bucket será ativado. Por exemplo, /path/to/mount/point.

Pré-preencher o cache de metadados

Antes de executar uma carga de trabalho, recomendamos pré-preencher o cache de metadados, o que melhora significativamente o desempenho e reduz substancialmente o número de chamadas de metadados para o Cloud Storage, principalmente se o campo implicit-dirs ou a opção --implicit-dirs forem usados. O driver CSI do Cloud Storage FUSE para GKE fornece uma API que processa o pré-preenchimento do cache de metadados. Consulte Usar a pré-busca de metadados para pré-preencher o cache de metadados.

Para pré-preencher o cache de metadados, use um dos seguintes métodos:

Google Kubernetes Engine

Defina a flag do atributo de volume CSI gcsfuseMetadataPrefetchOnMount como true:

Nas versões 1.32.1-gke.1357001 ou mais recentes do Google Kubernetes Engine, é possível ativar o pré-busca de metadados para um determinado volume usando a opção de configuração gcsfuseMetadataPrefetchOnMount no campo volumeAttributes da definição de PersistentVolume. O método initContainer não é necessário quando você usa a opção de configuração gcsfuseMetadataPrefetchOnMount.

  apiVersion: v1
  kind: PersistentVolume
  metadata:
    name: training-bucket-pv
  spec:
    ...
    csi:
      volumeHandle: BUCKET_NAME
      volumeAttributes:
        ...
        gcsfuseMetadataPrefetchOnMount: "true"
  

Substitua:

  • BUCKET_NAME é o nome do bucket.

Os recursos do contêiner de inicialização podem variar de acordo com o conteúdo do bucket e o layout hierárquico. Portanto, considere definir recursos de arquivo secundário de pré-busca de metadados personalizados para limites mais altos.

Linux

Execute manualmente o comando ls -R no ponto de montagem do Cloud Storage FUSE para listar recursivamente todos os arquivos e pré-preencher o cache de metadados:

ls -R MOUNT_POINT > /dev/null

Substitua:

MOUNT_POINT: o caminho para o ponto de montagem do Cloud Storage FUSE.

Compute Engine

Execute manualmente o comando ls -R no ponto de montagem do Cloud Storage FUSE para listar recursivamente todos os arquivos e pré-preencher o cache de metadados:

ls -R MOUNT_POINT > /dev/null

Substitua:

MOUNT_POINT: o caminho para o ponto de montagem do Cloud Storage FUSE.

Ativar o armazenamento em cache de arquivos e os downloads paralelos

Com o armazenamento em cache de arquivos, é possível armazenar dados de arquivos acessados com frequência localmente na sua máquina, acelerando as leituras repetidas e reduzindo os custos do Cloud Storage. Quando você ativa o armazenamento em cache de arquivos, os downloads paralelos também são ativados automaticamente. Os downloads paralelos usam vários workers para baixar um arquivo em paralelo usando o diretório de cache de arquivos como um buffer de pré-busca, resultando em um tempo de carregamento do modelo nove vezes mais rápido.

Para saber como ativar e configurar o armazenamento em cache de arquivos e os downloads paralelos, consulte Ativar e configurar o comportamento do armazenamento em cache de arquivos. Para usar uma configuração de exemplo, consulte Exemplo de configuração para ativar o armazenamento em cache de arquivos e downloads paralelos.

Considerações sobre Cloud GPUs e Cloud TPU para usar o cache de arquivos e downloads paralelos

O cache de arquivos pode ser hospedado em SSDs locais, RAM, Persistent Disk ou Google Cloud Hyperdisk com as orientações a seguir. Em todos os casos, os dados ou o arquivo grande individual precisam caber na capacidade disponível do diretório de cache de arquivos, que é controlada usando o campo max-size-mb ou a opção --file-cache-max-size-mb.

Considerações sobre Cloud GPUs

Os SSDs locais são ideais para dados de treinamento e downloads de checkpoints. Os tipos de máquina das Cloud GPUs incluem capacidade de SSD que pode ser usada, como os tipos de máquina A4, que incluem 12 TiBs de SSD.

  • Um disco de RAM oferece o melhor desempenho para carregar pesos de modelo devido ao tamanho pequeno em comparação com a quantidade de RAM não utilizada no sistema.

  • O Persistent Disk ou o Google Cloud Hyperdisk podem ser usados como um cache.

Considerações sobre a Cloud TPU

A Cloud TPU não são compatíveis com SSDs locais. Se você usar o cache de arquivos no Cloud TPU sem modificação, o local padrão usado será o volume de inicialização, o que não é recomendado e resulta em desempenho ruim.

Em vez do volume de inicialização, recomendamos o uso de um disco RAM, que é preferível pelo desempenho e por não ter custo incremental. No entanto, um disco de RAM geralmente tem tamanho limitado e é mais útil para disponibilizar pesos de modelo ou downloads de checkpoint, dependendo do tamanho do checkpoint e da RAM disponível. Além disso, recomendamos o uso do Persistent Disk e do Google Cloud Hyperdisk para fins de armazenamento em cache.

Exemplo de configuração para ativar o armazenamento em cache de arquivos e downloads paralelos

Por padrão, o cache de arquivos usa um SSD local se o modo ephemeral-storage-local-ssd estiver ativado para o nó do Google Kubernetes Engine. Se nenhum SSD local estiver disponível, por exemplo, em máquinas do Cloud TPU, o cache de arquivos usará o disco de inicialização do nó do Google Kubernetes Engine, o que não é recomendado. Nesse caso, você pode usar um disco RAM como o diretório de cache, mas considere a quantidade de RAM disponível para o cache de arquivos em comparação com o que é necessário para o pod.

Opções de gcsfuse

gcsfuse --file-cache-max-size-mb=-1 \
      --file-cache-cache-file-for-range-read=true \
      --file-cache-enable-parallel-downloads=true \
      BUCKET_NAME

Substitua:

  • BUCKET_NAME é o nome do bucket.

Arquivo de configuração

file-cache:
  max-size-mb: -1
  cache-file-for-range-read: true
  enable-parallel-downloads: true

Cloud GPUs

mountOptions:
    - file-cache:max-size-mb:-1
    - file-cache:cache-file-for-range-read:true
    - file-cache:enable-parallel-downloads:true

# RAM disk file cache if LSSD not available. Uncomment to use
# volumes:
#   - name: gke-gcsfuse-cache
#     emptyDir:
#       medium: Memory

Cloud TPU

mountOptions:
    - file-cache:max-size-mb:-1
    - file-cache:cache-file-for-range-read:true
    - file-cache:enable-parallel-downloads:true

volumes:
    - name: gke-gcsfuse-cache
      emptyDir:
        medium: Memory

Compute Engine

gcsfuse --file-cache-max-size-mb=-1 \
      --file-cache-cache-file-for-range-read=true \
      --file-cache-enable-parallel-downloads=true \
      BUCKET_NAME MOUNT_POINT

Substitua:

  • BUCKET_NAME é o nome do bucket.

  • MOUNT_POINT é o diretório local em que o bucket será ativado. Por exemplo, /path/to/mount/point.

Desativar entradas de cache de estatísticas negativas

Por padrão, o Cloud Storage FUSE armazena em cache entradas de estatísticas negativas, ou seja, entradas de arquivos que não existem, com um TTL de cinco segundos. Em cargas de trabalho em que os arquivos são criados ou excluídos com frequência, como a criação de checkpoints distribuídos, essas entradas em cache podem ficar desatualizadas rapidamente, o que leva a problemas de desempenho. Para evitar isso, recomendamos desativar o cache de estatísticas negativas para cargas de trabalho de treinamento, disponibilização e checkpoint usando o campo negative-ttl-secs ou a opção --metadata-cache-negative-ttl-secs.

Use as instruções a seguir para desativar o cache de estatísticas negativas:

Opção gcsfuse

gcsfuse --metadata-cache-negative-ttl-secs=0 \
  BUCKET_NAME

Substitua:

  • BUCKET_NAME é o nome do bucket.

Arquivo de configuração

metadata-cache:
 negative-ttl-secs: 0

Google Kubernetes Engine

mountOptions:
    - metadata-cache:negative-ttl-secs:0

Compute Engine

gcsfuse --metadata-cache-negative-ttl-secs=0 \
  BUCKET_NAME MOUNT_POINT

Substitua:

  • BUCKET_NAME é o nome do bucket.

  • MOUNT_POINT é o diretório local em que o bucket será ativado. Por exemplo, /path/to/mount/point.

Ativar gravações de streaming

As gravações de streaming fazem upload dos dados diretamente para o Cloud Storage à medida que são gravados, o que reduz a latência e o uso de espaço em disco. Isso é especialmente útil para gravações grandes e sequenciais, como pontos de verificação. As gravações de streaming são ativadas por padrão no Cloud Storage FUSE versão 3.0 e mais recente.

Se as gravações de streaming não estiverem ativadas por padrão, siga estas instruções para ativá-las. Para ativar gravações de streaming, é necessário ter o Cloud Storage FUSE versão 3.0, disponível no Google Kubernetes Engine versões 1.32.1-gke.1729000 ou mais recentes.

Opção gcsfuse

gcsfuse --enable-streaming-writes=true \
  BUCKET_NAME

Substitua:

  • BUCKET_NAME é o nome do bucket.

Arquivo de configuração

write:
 enable-streaming-writes: true

Google Kubernetes Engine

mountOptions:
    - write:enable-streaming-writes:true

Compute Engine

gcsfuse --enable-streaming-writes=true \
  BUCKET_NAME MOUNT_POINT

Substitua:

  • BUCKET_NAME é o nome do bucket.

  • MOUNT_POINT é o diretório local em que o bucket será ativado. Por exemplo, /path/to/mount/point.

Ativar leituras em buffer

As leituras em buffer podem melhorar o desempenho de leitura sequencial de arquivos grandes em duas a cinco vezes, pré-buscando de forma assíncrona partes de um objeto do Cloud Storage em um buffer na memória. Isso permite que as leituras subsequentes sejam exibidas do buffer, em vez de exigir chamadas de rede.

Considere o seguinte antes de ativar as leituras em buffer:

  • Leituras em buffer são incompatíveis com o cache de arquivos. Se as leituras em buffer e o armazenamento em cache de arquivos estiverem ativados, o armazenamento em cache de arquivos terá precedência e as leituras em buffer serão ignoradas.

  • As leituras em buffer podem consumir muitos recursos de memória e computação.

Para ativar as leituras em buffer, use as seguintes instruções:

Opções da CLI

gcsfuse --enable-buffered-read=true \
  BUCKET_NAME

Substitua:

  • BUCKET_NAME é o nome do bucket.

Arquivo de configuração

read:
 enable-buffered-read: true

Aumentar o tamanho de leitura antecipada do kernel

Para cargas de trabalho que envolvem principalmente leituras sequenciais de arquivos grandes, como veiculação e restaurações de pontos de controle, aumentar o tamanho de leitura antecipada pode melhorar significativamente o desempenho. Isso pode ser feito usando o parâmetro do kernel do Linux read_ahead_kb na máquina local. Recomendamos que você aumente o parâmetro do kernel read_ahead_kb para 1 MB em vez de usar a quantidade padrão de 128 KB definida na maioria das distribuições do Linux. Para instâncias do Compute Engine, as permissões sudo ou root são necessárias para aumentar o parâmetro do kernel.

Para aumentar o parâmetro de kernel read_ahead_kb para 1 MB em um diretório específico montado no Cloud Storage FUSE, use as instruções a seguir. O bucket precisa ser montado no Cloud Storage FUSE antes de executar o comando. Caso contrário, o parâmetro do kernel não vai aumentar.

Para buckets zonais, o Cloud Storage FUSE gerencia automaticamente o parâmetro de kernel read_ahead_kb no Google Kubernetes Engine versão 1.35.0-gke.3047001 ou posterior e em ambientes do Compute Engine que usam o Cloud Storage FUSE versão 3.7.0 ou posterior. Como isso é feito automaticamente, a opção de montagem read_ahead_kb não é mais aplicável. Qualquer valor fornecido será ignorado. Em ambientes do Compute Engine, o Cloud Storage FUSE requer permissões de raiz ou sudo sem senha para gerenciar automaticamente esse parâmetro.

Google Kubernetes Engine

mountOptions:
    - read_ahead_kb=1024

Compute Engine

export MOUNT_POINT=/path/to/mount/point
echo 1024 | sudo tee /sys/class/bdi/0:$(stat -c "%d" $MOUNT_POINT)/read_ahead_kb

Substitua:

  • /path/to/mount/point: o caminho no sistema de arquivos local em que o bucket do Cloud Storage está montado.

Desativar o Security Token Service para evitar verificações redundantes

O driver CSI do Cloud Storage FUSE para o Google Kubernetes Engine tem verificações de acesso para garantir a recuperabilidade do pod devido à configuração incorreta do usuário das vinculações de identidade da carga de trabalho entre o bucket e a conta de serviço do GKE, que podem atingir as cotas padrão da API Security Token Service em escala. Isso pode ser desativado definindo o atributo de volume skipCSIBucketAccessCheck do driver CSI de volume permanente. Recomendamos que você verifique se a conta de serviço do GKE tem o acesso correto ao bucket do Cloud Storage de destino para evitar falhas de montagem do pod.

Além disso, a cota do Security Token Service precisa ser aumentada além do valor padrão de 6000 se um cluster do Google Kubernetes Engine tiver mais de 6.000 nós, o que pode resultar em erros 429 se não for aumentada em implantações em grande escala. A cota do Security Token Service precisa ser aumentada na página "Cotas e limites". Recomendamos que você mantenha a cota igual ao número de montagens. Por exemplo, se houver 10.000 montagens no cluster, a cota precisará ser aumentada para 10000.

Para definir o atributo de volume skipCSIBucketAccessCheck, consulte o seguinte exemplo de configuração:

  volumeAttributes:
      - skipCSIBucketAccessCheck: "true"
   

Otimizar o desempenho dos checkpoints do Orbax do OCDBT

Para cargas de trabalho que usam checkpoints do Orbax formatados em OCDBT, é possível melhorar o desempenho de veiculação e restauração de checkpoint usando as seguintes orientações:

  • Defina as huge pages transparentes como always: definir as huge pages transparentes como always melhora o desempenho, reduzindo a fragmentação de memória e as chamadas do sistema. Essa configuração é mais eficaz quando grandes blocos de memória são alocados, o que é comum nessas cargas de trabalho. Essa configuração é definida por padrão em máquinas do Cloud TPU e só precisa ser definida em outros tipos de máquina. Para ativar grandes páginas transparentes na máquina local, execute o seguinte comando com permissões root.

    echo always | tee /sys/kernel/mm/transparent_hugepage/enabled
    

    Em um ambiente do GKE, é possível criar um pod privilegiado para fazer a mesma coisa.

  • Aumentar o tamanho da leitura antecipada do kernel: aumentar o tamanho da leitura antecipada do kernel para 1.024 KB melhora o desempenho da leitura sequencial. Para mais informações, consulte Aumentar o tamanho de leitura antecipada do kernel.

  • Defina ocdbt_target_data_file_size como 200 MiB: defina ocdbt_target_data_file_size como 200 MiB, que é o ideal para o desempenho de leitura com o Cloud Storage FUSE.

  • Use o cache de DNS: ele reduz a latência armazenando em cache as buscas DNS localmente. No GKE, é possível ativar o NodeLocal DNSCache para armazenar em cache as buscas DNS. Como alternativa, use o Cloud Storage FUSE versão 3.5 ou mais recente no Compute Engine ou o GKE versão 1.34.1-gke.3899000 ou mais recente em um ambiente do GKE.

Outras considerações sobre desempenho

Além das otimizações principais discutidas, vários outros fatores podem afetar significativamente o desempenho geral do Cloud Storage FUSE. As seções a seguir descrevem outras considerações de desempenho que recomendamos ao usar o Cloud Storage FUSE.

Aumentar o limite de renomeação para buckets não HNS

As cargas de trabalho de checkpoint sempre devem ser feitas com um bucket que tenha o namespace hierárquico ativado devido a renomeações atômicas e mais rápidas e QPS mais altas para leituras e gravações. No entanto, se você aceitar o risco de as renomeações de diretório não serem atômicas e demorarem mais, use o campo rename-dir-limit ou a opção --rename-dir-limit se estiver realizando checkpoints usando buckets sem namespace hierárquico para especificar um limite no número de arquivos ou operações envolvidos em uma operação de renomeação de diretório em um determinado momento.

Recomendamos especificar um valor alto para essa configuração para evitar falhas de checkpoint. Como o Cloud Storage FUSE usa um namespace simples e os objetos são imutáveis, uma operação de renomeação de diretório envolve renomear e excluir todos os arquivos individuais dentro do diretório. É possível controlar o número de arquivos afetados por uma operação de renomeação definindo a opção rename-dir-limit gcsfuse.

Use as instruções a seguir para definir a opção de configuração rename-dir-limit:

Opção gcsfuse

gcsfuse --rename-dir-limit=200000 \
  BUCKET_NAME

Substitua:

  • BUCKET_NAME é o nome do bucket.

Arquivo de configuração

file-system:
 rename-dir-limit: 200000

Google Kubernetes Engine

mountOptions:
    - rename-dir-limit=200000

Compute Engine

gcsfuse --rename-dir-limit=200000 \
  BUCKET_NAME MOUNT_POINT

Substitua:

  • BUCKET_NAME é o nome do bucket.

  • MOUNT_POINT é o diretório local em que o bucket será ativado. Por exemplo, /path/to/mount/point.

Armazenamento em cache da lista de kernels

O cache de lista é um cache para respostas de lista de diretórios e arquivos, ou ls, que melhora a velocidade das operações de lista. Ao contrário do cache de estatísticas, que é gerenciado pelo Cloud Storage FUSE, o cache de lista é mantido no cache de página do kernel e controlado pelo kernel com base na disponibilidade de memória.

Ativar o armazenamento em cache da lista de kernels é mais benéfico para os seguintes casos de uso:

  • Cargas de trabalho com listagens de diretórios repetidas: essa configuração é especialmente útil para cargas de trabalho que realizam listagens completas de diretórios com frequência, como execuções de treinamento de IA/ML. Isso pode beneficiar as cargas de trabalho de exibição e treinamento.

  • Montagens somente leitura: o armazenamento em cache de listas é recomendado com montagens somente leitura para evitar problemas de consistência.

A ativação do armazenamento em cache da lista de kernel deve ser feita com cautela e só deve ser usada se o sistema de arquivos for realmente somente leitura, sem alterações esperadas no conteúdo do diretório durante a execução de um job. Isso ocorre porque, com essa flag, o aplicativo local nunca vê atualizações, especialmente se o TTL estiver definido como -1.

Por exemplo, o Cliente 1 lista directoryA, o que faz com que directoryA seja um residente no cache da lista do kernel. O cliente 2 cria fileB em directoryA no bucket do Cloud Storage. O Cliente 1 verifica continuamente se há fileB em directoryA, o que é essencialmente verificar a entrada de cache da lista do kernel e nunca passa pela rede. O cliente 1 não vê que um novo arquivo está no diretório porque a lista de arquivos é fornecida continuamente do cache de lista do kernel local. Cliente 1 expira, e o programa é interrompido.

Use a seguinte instrução para ativar o armazenamento em cache de listas:

Opção gcsfuse

gcsfuse --kernel-list-cache-ttl-secs=-1 \
  BUCKET_NAME

Substitua:

  • BUCKET_NAME é o nome do bucket.

Arquivo de configuração

file-system:
 kernel-list-cache-ttl-secs: -1

Google Kubernetes Engine

mountOptions:
    - file-system:kernel-list-cache-ttl-secs:-1

Compute Engine

gcsfuse --kernel-list-cache-ttl-secs=-1 \
  BUCKET_NAME MOUNT_POINT

Substitua:

  • BUCKET_NAME é o nome do bucket.

  • MOUNT_POINT é o diretório local em que o bucket será ativado. Por exemplo, /path/to/mount/point.

Quando você usa a opção de montagem file-system:kernel-list-cache-ttl-secs, os valores significam o seguinte:

  • Um valor positivo representa o TTL em segundos para manter a resposta da lista de diretórios no cache de páginas do kernel.

  • Um valor de -1 ignora a expiração da entrada e retorna a resposta da lista do cache quando ela está disponível.

Usar o cache de compilação persistente (JIT) do JAX com o Cloud Storage FUSE

O JAX é compatível com o cache Just-In-Time (JIT), um cache de compilação persistente opcional que armazena artefatos de função compilados. Ao usar esse cache, você pode acelerar significativamente as execuções de script subsequentes, evitando etapas de compilação redundantes.

Para ativar o armazenamento em cache JIT, é necessário atender aos seguintes requisitos:

  • Use a versão mais recente do JAX: use as versões 0.5.1 ou mais recentes do JAX para ter acesso aos recursos e otimizações de cache mais recentes.

  • Maximize a capacidade do cache: para evitar a degradação do desempenho devido à remoção do cache, defina um tamanho de cache ilimitado, principalmente se você quiser substituir as configurações padrão. Para isso, defina a variável de ambiente:

    export JAX_COMPILATION_CACHE_MAX_SIZE=-1
    
  • Verifique o YAML do pod de checkpoint: use a configuração de checkpoint para o ponto de montagem do cache JIT do JAX.

Configurar o Receive Flow Steering (RFS) para A4X

Nas instâncias do Compute Engine, o Receive Packet Steering (RPS) e o Receive Flow Steering (RFS) trabalham juntos para melhorar o desempenho da rede, distribuindo de maneira inteligente o processamento de pacotes de rede em várias CPUs. Recomendamos essas configurações para tráfego de rede de alta taxa em tipos de máquina como A4X.

  • O RPS distribui os pacotes de rede recebidos em diferentes CPUs para processamento. Isso ajuda a equilibrar a carga e evita que uma única CPU se torne um gargalo, o que é especialmente útil para tráfego de rede de alta taxa e pode contribuir para uma latência menor.

  • O RFS se baseia no RPS para reduzir ainda mais a latência da rede, melhorando a eficiência do cache da CPU. Ele direciona os pacotes para o núcleo de CPU específico em que o aplicativo que vai consumir os pacotes está em execução, o que aumenta a taxa de ocorrência em cache de dados da CPU e reduz a latência da rede.

Benefícios de performance

O RFS melhora significativamente o desempenho em várias cargas de trabalho, aumentando a capacidade de processamento em até 40%.

Considerações

Embora sejam eficazes sob carga, essas configurações podem não ser úteis em todos os cenários:

  • Cargas de trabalho de thread único ou fluxo único:uma carga de trabalho de fluxo único ocorre quando todo o tráfego de rede usa uma única conexão de rede (por exemplo, uma única transferência de arquivos em massa por uma conexão TCP). Esses aplicativos geralmente têm pouco benefício e podem até mesmo sofrer uma pequena diminuição na taxa de transferência (por exemplo, ~7,7% em testes específicos do nginx). Os aplicativos de fluxo único geralmente são raros em contextos de alto desempenho.

  • Migração frequente de linhas de execução:se as linhas de execução do aplicativo se moverem com frequência entre CPUs, o RFS vai atualizar constantemente os mapeamentos de CPU(por exemplo, aplicativos que usam pools de linhas de execução de worker dinâmicos grandes em que as solicitações são transferidas com frequência entre diferentes núcleos), o que pode levar a um tráfego excessivo entre CPUs e reordenação de pacotes.

Script de configuração

Execute o script a seguir no sistema operacional convidado da instância do Compute Engine. O script requer permissões sudo ou root para modificar parâmetros do kernel.

O script ativa o RPS, mapeia as filas de rede para as CPUs disponíveis de maneira rotativa e define o tamanho da tabela de fluxo por fila como 65536.

#!/bin/bash
set -e

# Note: This script uses 'apt' and is intended for Debian-based systems.
# If 'iproute2' is not found, you may need to run 'sudo apt update' first.
sudo apt install -y iproute2

# This script enables and configures RPS (Receive Packet Steering) and RFS
# (Receive Flow Steering) for the primary network interface.
# It creates a 1:1 mapping of CPUs to receive queues and sets a specific
# flow count for each queue.

# --- Configuration ---
# The desired number of flow entries per receive queue.
RPS_FLOW_CNT_PER_QUEUE=65536

# --- Script Body ---

# 1. Auto-detect the primary network interface.
INTERFACE=$(ip route | grep default | awk '{print $5}' | head -n 1)

if [ -z "$INTERFACE" ]; then
  echo "Error: Could not determine the primary network interface."
  exit 1
fi
echo "Primary network interface detected: $INTERFACE"

echo "Starting RPS/RFS configuration for interface: $INTERFACE"

# 2. Determine the number of receive queues for the interface.
NUM_QUEUES=$(ls -d /sys/class/net/$INTERFACE/queues/rx-* 2>/dev/null | wc -l)
if [ "$NUM_QUEUES" -eq 0 ]; then
  echo "Error: No receive queues found for interface $INTERFACE."
  echo "Please check if the network driver supports multi-queue."
  exit 1
fi
echo "Found $NUM_QUEUES receive queues for interface $INTERFACE."

# 3. Determine the number of CPUs.
NUM_CPUS=$(nproc)
if [ -z "$NUM_CPUS" ] || [ "$NUM_CPUS" -eq 0 ]; then
  echo "Error: Could not determine the number of CPUs."
  exit 1
fi
echo "Found $NUM_CPUS CPUs."

# 4. Calculate and set the total socket flow entries.
# This is the total number of entries in the global socket flow table.
RPS_SOCK_FLOW_ENTRIES=$((NUM_QUEUES * RPS_FLOW_CNT_PER_QUEUE))
echo "Setting the total RPS socket flow entries to $RPS_SOCK_FLOW_ENTRIES..."
if ! echo "$RPS_SOCK_FLOW_ENTRIES" | sudo tee /proc/sys/net/core/rps_sock_flow_entries > /dev/null; then
  echo "Error: Failed to set rps_sock_flow_entries. Please run with sufficient privileges."
  exit 1
fi

# 5. Configure each receive queue.
for i in $(seq 0 $((NUM_QUEUES - 1))); do
  RX_QUEUE="/sys/class/net/$INTERFACE/queues/rx-$i"

  # a) Assign a CPU to this queue (round-robin).
  CPU_INDEX=$((i % NUM_CPUS))
  CPU_BITMAP_HEX=$(printf '%x' $((1 << CPU_INDEX)))
  echo "Assigning CPU $CPU_INDEX (bitmap: $CPU_BITMAP_HEX) to queue rx-$i"
  if ! echo "$CPU_BITMAP_HEX" | sudo tee "$RX_QUEUE/rps_cpus" > /dev/null; then
    echo "Error writing bitmap to $RX_QUEUE/rps_cpus"
    exit 1
  fi

  # b) Set the flow count for this queue.
  echo "Setting flow count for $RX_QUEUE to $RPS_FLOW_CNT_PER_QUEUE"
  if ! echo "$RPS_FLOW_CNT_PER_QUEUE" | sudo tee "$RX_QUEUE/rps_flow_cnt" > /dev/null; then
    echo "Error writing to $RX_QUEUE/rps_flow_cnt"
    exit 1
  fi
done

echo "RPS and RFS configuration updated successfully for $INTERFACE."

A seguir