terça-feira, 8 de março de 2016

Squid 4 + systemd: combinação que funciona

Até o Squid 3.5, o comportamento do daemon é incompatível com inits modernos e exige gambiarras ou funcionalidade limitada (-N).

Recapitulando como é até a versão 3.5:

PID1
 \_ MASTER/PARENT
     \_ WORKER <--- PROCESSO PAI DE FATO (ARQUIVO PID)
         \_ FILHO 1
         \_ FILHO 2
            ...

No Squid 4, beta enquanto escrevo, é assim:

PID1
 \_ MASTER/PARENT <--- PROCESSO PAI DE FATO (ARQUIVO PID)
     \_ WORKER
         \_ FILHO 1
         \_ FILHO 2
            ...

Ou seja, o processo a ser monitorado (e sinalizado) passou a ser filho direto do init, que agora pode fazê-lo via SIGCHLD. Portanto, usando Type=forking e rodando o daemon sem a opção -N, temos uma configuração funcional. Continua não bloqueando ao receber SIGTERM; o systemd, mesmo assim, aguarda o processo principal terminar, sendo finalizado corretamente. E, sem -N, o modo de múltiplos processos funciona.

Desde a versão 3.5.11, o daemon não morre mais se receber SIGHUP antes de completar a inicialização. Geralmente um shell script, em /etc/NetworkManager/dispatcher.d, chama systemctl reload squid.service toda vez que a configuração de rede mudar (por causa dos servidores DNS em particular). Levando em conta que o NetworkManager é executado pouco antes do Squid, o sinal vinha de forma aleatória, potencialmente matando-o.

Restava um problema: criação da estrutura do cache em disco (cache_dir em /etc/squid/squid.conf). squid -z realiza a daemonização logo no início chamando fork() e exit(), com objetivo de desligar-se do processo que o executou e tornar-se filho do init. Esse comportamento é esperado com Type=forking. Porém squid -z é executado antes do daemon em si, posto num shell script em ExecStartPre=. Cria a estrutura quando não existir e depois finaliza-se. ExecStartPre= comporta-se como um serviço Type=oneshot. O systemd executa o que estiver ali e, no momento em que o processo finalizar (não importando se existirem filhos ainda rodando), considera-o terminado e mata tudo antes de passar para ExecStart=.

Precisávamos fazer squid -z esperar seus filhos terminarem. A partir da versão 4.0.8, temos a nova opção --foreground para tal fim.

Então, basta rodar squid --foreground -z em ExecStartPre= e está resolvido.

Nenhum comentário:

Postar um comentário