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