Workers multiplex (recurso experimental)

Informar um problema Acessar a origem

Nesta página, descrevemos workers multiplex, como escrever regras compatíveis com multiplex e soluções alternativas para algumas limitações.

Os Workers multiplex permitem que o Bazel processe várias solicitações com um único processo de worker. Para workers com várias linhas de execução, o Bazel pode usar menos recursos para alcançar um desempenho igual ou melhor. Por exemplo, em vez de ter um processo de worker por worker, o Bazel pode ter quatro workers multiplexados conversando com o mesmo processo de worker, que pode processar solicitações em paralelo. Para linguagens como Java e Scala, isso economiza o tempo de aquecimento da JVM e o tempo de compilação JIT, além de permitir o uso de um cache compartilhado entre todos os workers do mesmo tipo.

Informações gerais

Há duas camadas entre o servidor do Bazel e o processo do worker. Para determinadas mneumônicas que podem executar processos em paralelo, o Bazel recebe um WorkerProxy do pool de workers. O WorkerProxy encaminha solicitações para o processo de worker sequencialmente com um request_id. Ele processa a solicitação e envia respostas para o WorkerMultiplexer. Quando o WorkerMultiplexer recebe uma resposta, ele analisa o request_id e encaminha as respostas de volta para o WorkerProxy correto. Assim como os workers não multiplexados, toda a comunicação é feita por entrada/saída padrão, mas a ferramenta não pode apenas usar stderr para saída visível ao usuário (veja abaixo).

Cada worker tem uma chave. O Bazel usa o código hash da chave (composto por variáveis de ambiente, a raiz de execução e o mnemônico) para determinar qual WorkerMultiplexer usar. WorkerProxys se comunicam com o mesmo WorkerMultiplexer se tiverem o mesmo código hash. Portanto, supondo que as variáveis de ambiente e a raiz de execução sejam as mesmas em uma única invocação do Bazel, cada mnemônico exclusivo só pode ter um WorkerMultiplexer e um processo de worker. O número total de workers, incluindo workers normais e WorkerProxys, ainda é limitado por --worker_max_instances.

Como criar regras compatíveis com multiplex

O processo do worker da regra precisa ter várias linhas de execução para aproveitar os workers multiplex. O Protobuf permite que um conjunto de regras analise uma única solicitação, mesmo que possa haver várias solicitações se acumulando no stream. Sempre que o processo de worker analisa uma solicitação do stream, ele precisa processá-la em uma nova linha de execução. Como linhas de execução diferentes podem ser concluídas e gravar no stream ao mesmo tempo, o processo do worker precisa garantir que as respostas sejam escritas atomicamente (as mensagens não se sobreponham). As respostas precisam conter o request_id da solicitação que estão processando.

Como gerenciar a saída multiplex

Os workers multiplex precisam ter mais cuidado ao processar a saída do que os singleplex. Tudo o que for enviado para stderr entrará em um único arquivo de registro compartilhado entre todos os WorkerProxys do mesmo tipo, intercalado aleatoriamente entre solicitações simultâneas. Embora redirecionar stdout para stderr seja uma boa ideia, não colete essa saída no campo output de WorkResponse, porque isso pode mostrar ao usuário partes da saída corrompidas. Se sua ferramenta enviar apenas saída orientada ao usuário para stdout ou stderr, será necessário alterar esse comportamento antes de ativar workers multiplex.

Como ativar workers multiplex

Os workers multiplex não estão ativados por padrão. Um conjunto de regras pode ativar workers multiplex usando a tag supports-multiplex-workers no execution_requirements de uma ação (assim como a tag supports-workers ativa workers normais). Como acontece com o uso de workers comuns, uma estratégia de worker precisa ser especificada no nível do conjunto de regras (por exemplo, --strategy=[some_mnemonic]=worker) ou geralmente no nível da estratégia (por exemplo, --dynamic_local_strategy=worker,standalone). Nenhuma outra flag é necessária, e supports-multiplex-workers tem precedência sobre supports-workers, se ambas estiverem definidas. Desative os workers multiplex globalmente transmitindo --noworker_multiplex.

Recomendamos que um conjunto de regras use workers multiplex, se possível, para reduzir a pressão da memória e melhorar o desempenho. No entanto, os workers multiplex não são atualmente compatíveis com a execução dinâmica, a menos que implementem o sandbox multiplex. A tentativa de executar workers multiplex sem sandbox com execução dinâmica usará silenciosamente os workers do singleplex em sandbox.

Sandbox multiplex

Os workers multiplex podem ser colocados no sandbox adicionando suporte explícito a eles nas implementações do worker. O sandbox de worker singleplex pode ser feito executando cada processo do worker no próprio sandbox. Já os workers multiplex compartilham o diretório de trabalho do processo entre várias solicitações paralelas. Para permitir o sandbox de workers multiplex, eles precisam ser compatíveis com a leitura e a gravação em um subdiretório especificado em cada solicitação, em vez de diretamente no diretório de trabalho.

Para oferecer suporte ao sandbox multiplex, o worker precisa usar o campo sandbox_dir de WorkRequest e usá-lo como um prefixo para todas as leituras e gravações de arquivos. Os campos arguments e inputs permanecem inalterados de uma solicitação fora do sandbox, mas as entradas reais são relativas a sandbox_dir. O worker precisa converter os caminhos de arquivos encontrados em arguments e inputs para ler esse caminho modificado e gravar todas as saídas relativas ao sandbox_dir. Isso inclui caminhos como ".", bem como caminhos encontrados em arquivos especificados nos argumentos (como "argfile").

Quando um worker é compatível com o sandbox multiplex, o conjunto de regras pode declarar esse suporte adicionando supports-multiplex-sandboxing ao execution_requirements de uma ação. O Bazel vai usar o sandbox multiplex se a sinalização --experimental_worker_multiplex_sandboxing for transmitida ou se o worker for usado com a execução dinâmica.

Os arquivos de um worker multiplex no sandbox ainda estão relacionados ao diretório de trabalho do processo do worker. Assim, se um arquivo for usado tanto para executar o worker como como uma entrada, ele precisará ser especificado como uma entrada no argumento do flagfile e em tools, executable ou runfiles.