Daemon do Squid em inits modernos
O Squid pode operar em dois modos no que diz respeito à forma do daemon: com a opção
Com
Sem
Os problemas insolúveis são dois:
- O processo que deve ser sinalizado (worker) não é filho direto do init. Isso impede o systemd monitorá-lo eficazmente via SIGCHLD. Ele lhe avisa com "squid.service: Supervising process XXX which is not our child. We'll most likely not notice when it exits.". A útil opção
- Ao receber SIGTERM, o processo worker retorna imediatamente.
O systemd finaliza daemons assim:
- Executa, caso exista, o comando configurado em
- Envia, caso ainda existam processos no cgroup daquele serviço após
- Depois de um temporizador (90s, configurável), caso ainda existam processos, envia SIGKILL (obedecendo à configuração acima). A partir da versão 209, temos
No arquivo de configuração do Squid existe a opção
As duas soluções possíveis, que demandam modificações no código do Squid:
- Fazer o modo de múltiplos processos funcionar sem daemonização (
- Fazer o processo worker retornar ao ser sinalizado com SIGTERM apenas quando finalizar por completo. Continuaria sendo uma configuração capenga (o processo a ser monitorado não seria um filho do init), porém pelo menos funcionaria com
No tempo das cavernas do SysV, era usada alguma gambiarra como isto:
Ou seja, era colocado um valor alto o suficiente em
Haja vista o exposto aqui, recomendo que, se você não precisar do modo de múltiplos processos, substitua o squid.service localmente na sua instalação por algo similar ao distribuído a partir da versão 3.5.0.4.
[1] Se não for especificado um arquivo pid com
-N ou sem ela.Com
-N, não é feito o processo de daemonização. É o preferido em inits modernos. Deve ser usado sempre que possível com o Upstart ou systemd. Contudo, o modo de múltiplos processos do Squid não funciona com -N até agora (3.5) e as distribuições, portanto, não podem usar por padrão.Sem
-N, ativa a daemonização. No systemd, isso significa um serviço Type=forking. À primeira vista, não haveria problema, pois existe compatibilidade. Não fosse o comportamento totalmente bugado do Squid ao funcionar dessa maneira.PID1
\_ MASTER/PARENT
\_ WORKER <--- PROCESSO PAI DE FATO (ARQUIVO PID)
\_ FILHO 1
\_ FILHO 2
...
Os problemas insolúveis são dois:
- O processo que deve ser sinalizado (worker) não é filho direto do init. Isso impede o systemd monitorá-lo eficazmente via SIGCHLD. Ele lhe avisa com "squid.service: Supervising process XXX which is not our child. We'll most likely not notice when it exits.". A útil opção
Restart= não funcionará.- Ao receber SIGTERM, o processo worker retorna imediatamente.
O systemd finaliza daemons assim:
- Executa, caso exista, o comando configurado em
ExecStop=.- Envia, caso ainda existam processos no cgroup daquele serviço após
ExecStop= finalizar, SIGTERM (ou o sinal configurado em KillSignal=) para todos (KillMode=control-group — padrão), apenas ao principal (KillMode=process) ou nenhum (KillMode=none). No caso de Type=forking, o processo principal é o presente no arquivo pid[1].- Depois de um temporizador (90s, configurável), caso ainda existam processos, envia SIGKILL (obedecendo à configuração acima). A partir da versão 209, temos
KillMode=mixed, que envia SIGTERM (ou o sinal configurado em KillSignal=) apenas ao processo principal e SIGKILL para todos após o temporizador.squid -k shutdown acha o PID do processo worker através do arquivo pid e envia SIGTERM ao mesmo. -k rotate faz o mesmo, mas usa SIGUSR1. -k reconfigure, por fim, SIGHUP. Poderíamos inferir que squid -k shutdown é desnecessário, já que podemos usar o mecanismo embutido de entrega de sinais do systemd (ajustando KillMode para process). Infelizmente, por causa do primeiro problema, ele não tem como saber quando o processo finalizou e mata imediatamente tudo que estiver no cgroup.No arquivo de configuração do Squid existe a opção
shutdown_lifetime (30 segundos se não for especificada), que faz o daemon esperar por determinado tempo até todos os clientes finalizarem suas conexões. Por causa do explicado acima, na prática, nunca é obedecida. O Squid nunca é finalizado corretamente.As duas soluções possíveis, que demandam modificações no código do Squid:
- Fazer o modo de múltiplos processos funcionar sem daemonização (
squid -N). Seria o ideal.- Fazer o processo worker retornar ao ser sinalizado com SIGTERM apenas quando finalizar por completo. Continuaria sendo uma configuração capenga (o processo a ser monitorado não seria um filho do init), porém pelo menos funcionaria com
ExecStop= presente.No tempo das cavernas do SysV, era usada alguma gambiarra como isto:
[...]
$SQUID -k shutdown -f $SQUID_CONF &
rm -f /var/lock/subsys/$SQUID
timeout=0
while : ; do
[ -f /var/run/squid.pid ] || break
if [ $timeout -ge $SQUID_SHUTDOWN_TIMEOUT ]; then
echo
return 1
fi
sleep 2 && echo -n "."
timeout=$((timeout+2))
done
echo_success
echo
[...]
Ou seja, era colocado um valor alto o suficiente em
$SQUID_SHUTDOWN_TIMEOUT (Fedora e RHEL antigos usavam 60 segundos), o script enviava SIGTERM (via squid -k shutdown) e ficava esperando e torcendo para que tudo desse certo (tipo "seja o que Deus quiser"). Como é que pode um sistema profissional usar uma coisa dessas?Haja vista o exposto aqui, recomendo que, se você não precisar do modo de múltiplos processos, substitua o squid.service localmente na sua instalação por algo similar ao distribuído a partir da versão 3.5.0.4.
[1] Se não for especificado um arquivo pid com
Type=forking, o systemd tenta adivinhar o processo principal (que no Squid fica sendo o master). Entretanto, o processo master não é o principal, que deve ser sinalizado e monitorado. No Fedora, por causa disso, propositadamente é suprimido PIDFile=. Uma bagunça!
Comentários
Postar um comentário