Nesta página, descrevemos os workers de multiplexação, como escrever regras compatíveis com multiplexação e soluções alternativas para algumas limitações.
Os multiplex workers permitem que o Bazel processe várias solicitações com um único processo de worker. Para trabalhadores multithread, o Bazel pode usar menos recursos para alcançar o mesmo desempenho ou um desempenho melhor. Por exemplo, em vez de ter um processo de worker por worker, o Bazel pode ter quatro workers multiplexados se comunicando com o mesmo processo de worker, que pode processar solicitações em paralelo. Para linguagens como Java e Scala, isso economiza tempo de inicialização da JVM e de compilação JIT. Em geral, permite usar um cache compartilhado entre todos os workers do mesmo tipo.
Visão geral
Há duas camadas entre o servidor do Bazel e o processo de worker. Para determinados
mnemônicos que podem executar processos em paralelo, o Bazel recebe um WorkerProxy
do
pool de workers. O WorkerProxy
encaminha solicitações ao processo de worker
sequencialmente junto com um request_id
. O processo de worker processa a solicitação
e envia respostas ao WorkerMultiplexer
. Quando o WorkerMultiplexer
recebe uma resposta, ele analisa o request_id
e encaminha as respostas
de volta para o WorkerProxy
correto. Assim como com os trabalhadores não multiplexados, toda a comunicação é feita por entrada/saída padrão, mas a ferramenta não pode usar apenas 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. Os WorkerProxy
s 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 trabalho. O número total de workers, incluindo regulares e
WorkerProxy
s, ainda é limitado por --worker_max_instances
.
Como escrever regras compatíveis com multiplex
O processo de worker da regra precisa ser multithread para aproveitar os workers de multiplex. O Protobuf permite que um conjunto de regras analise uma única solicitação, mesmo que haja várias solicitações acumuladas no fluxo. Sempre que o
processo de worker analisar uma solicitação do stream, ele precisará processar a solicitação em
uma nova linha de execução. Como diferentes linhas de execução podem ser concluídas e gravar no stream ao mesmo tempo, o processo do worker precisa garantir que as respostas sejam gravadas atomicamente (as mensagens não se sobrepõem). As respostas precisam conter o
request_id
da solicitação que estão processando.
Como processar a saída multiplex
Os trabalhadores multiplex precisam ter mais cuidado ao lidar com a saída do que os trabalhadores simplex. Tudo o que for enviado para stderr
vai para um único arquivo de registro
compartilhado entre todos os WorkerProxy
s do mesmo tipo,
intercalado aleatoriamente entre solicitações simultâneas. Embora seja uma boa ideia redirecionar stdout
para stderr
, não colete essa saída no campo output
de WorkResponse
, porque isso pode mostrar ao usuário partes corrompidas da saída.
Se a ferramenta enviar apenas saída orientada ao usuário para stdout
ou stderr
, você precisará mudar esse comportamento antes de ativar os workers de multiplex.
Como ativar workers multiplex
Os workers de multiplex não são ativados por padrão. Um conjunto de regras pode ativar workers de multiplex
usando a tag supports-multiplex-workers
no
execution_requirements
de uma ação, assim como a tag supports-workers
ativa workers regulares. Assim como acontece ao usar workers comuns, é necessário especificar uma estratégia de worker no nível do conjunto de regras (por exemplo, --strategy=[some_mnemonic]=worker
) ou no nível da estratégia (por exemplo, --dynamic_local_strategy=worker,standalone
). Não são necessárias flags adicionais, e supports-multiplex-workers
tem precedência sobre supports-workers
, se ambos estiverem definidos. É possível desativar os workers de multiplex
globalmente transmitindo --noworker_multiplex
.
É recomendável que um conjunto de regras use workers multiplexados, se possível, para reduzir a pressão na memória e melhorar o desempenho. No entanto, os workers de multiplex não são compatíveis com a execução dinâmica, a menos que implementem o isolamento em sandbox de multiplex. A tentativa de executar trabalhadores multiplex não em sandbox com execução dinâmica usará trabalhadores singleplex em sandbox sem aviso.
Sandbox multiplex
É possível colocar workers multiplexados em sandbox adicionando suporte explícito a eles nas implementações de worker. O isolamento de workers singleplex pode ser feito executando cada processo de worker na própria sandbox, mas os workers multiplex compartilham o diretório de trabalho do processo entre várias solicitações paralelas. Para permitir o sandboxing de workers de multiplexação, o worker precisa oferecer suporte à leitura e gravação em um subdiretório especificado em cada solicitação, em vez de diretamente no diretório de trabalho.
Para oferecer suporte ao isolamento de sandbox multiplex, o worker precisa usar o campo sandbox_dir
de WorkRequest
e usá-lo como prefixo para todas as leituras e gravações de arquivos.
Embora os campos arguments
e inputs
permaneçam inalterados em uma solicitação
sem sandbox, as entradas reais são relativas ao sandbox_dir
. O worker precisa traduzir os caminhos de arquivo encontrados em arguments
e inputs
para ler desse caminho modificado e também gravar todas as saídas relativas ao sandbox_dir
.
Isso inclui caminhos como ".", bem como caminhos encontrados em arquivos especificados
nos argumentos (como argumentos "argfile").
Quando um worker oferece suporte à sandbox de 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 multiplex sandboxing
se a flag --experimental_worker_multiplex_sandboxing
for transmitida ou se
o worker for usado com execução dinâmica.
Os arquivos de um worker multiplexado em sandbox ainda são relativos ao
diretório de trabalho do processo do worker. Assim, se um arquivo for
usado para executar o worker e como entrada, ele precisará ser especificado como
entrada no argumento flagfile e em tools
, executable
ou
runfiles
.