Una fallada en arrencar OpenVPN sovint arriba com una queixa de recursos acompanyada d’un suggeriment benintencionat de pujar algun límit, i el suggeriment només funciona aproximadament la meitat de les vegades. Darrere d’aquestes fallades hi ha dos comptadors sense relació. Un és un límit del nucli sobre el nombre de tasques que posseeix un identificador d’usuari real, i s’hereta quan s’executa el procés. L’altre és un pressupost de cgroup que el gestor de serveis aplica a una unitat i a tot el que aquesta bifurca. Llegir el valor efectiu de cadascun, per a la unitat que realment s’executa, costa menys que una conjectura.

Dos comptadors, dues preguntes

LimitNPROC és RLIMIT_NPROC sota un nom de systemd, i la seva unitat de comptabilitat és l’identificador d’usuari real. Cada procés que posseeix aquest usuari compta contra el mateix total, inclosa la feina iniciada per altres unitats, per una sessió d’inici o per una tasca del planificador. El límit, doncs, no és un sostre per servei encara que estigui definit dins d’una unitat de servei, i un servei que bifurca un auxiliar per a cada client competeix amb tota la resta que s’executa amb aquell compte. Una tasca cron ocupada sota el mateix usuari pot empènyer una unitat de VPN més enllà d’una línia que mai no va creuar tota sola.

TasksMax té un altre propietari: el controlador pids del cgroup de la unitat, que compta tasques en lloc de processos. Els fils són tasques, així que un dimoni que sembla d’un sol fil però té un conjunt de treballadors pot consumir un pressupost que, a primera vista, sembla molt més gran que el nombre de processos. EffectiveTasksMax informa del que la jerarquia de cgroup permet realment un cop els talls pares han dit la seva.

Per què l’excepció de root canvia la resposta

El nucli no aplica RLIMIT_NPROC a un procés que porta CAP_SYS_RESOURCE o CAP_SYS_ADMIN, i per això una unitat que s’executa com a root sense renunciar als privilegis queda efectivament sense límit per aquest paràmetre. Aquesta única excepció explica els consells contradictoris que la gent intercanvia: pujar LimitNPROC arregla un desplegament que va renunciar als privilegis i no fa absolutament res per a un que els va mantenir. Reviseu User= i si el dimoni canvia d’identitat després d’arrencar abans de donar mèrit o culpa a aquest paràmetre. Una unitat privilegiada que després passa a un compte sense privilegis torna a caure sota el límit en el moment del canvi, cosa que fa que la cronologia de la fallada també valgui la pena de llegir.

L’etapa de la fallada ho acota més. Un rebuig durant la preparació de l’execució, un error de bifurcació informat pel mateix dimoni i una creació de tasca rebutjada dins d’un cgroup produeixen línies de journal diferents, i només una d’elles es respon amb un pressupost més gran.

Llegeix els valors efectius, no els de l’intèrpret

ulimit -u d’un intèrpret interactiu descriu aquell intèrpret. No descriu què va passar el gestor de serveis al dimoni, i no diu res sobre la comptabilitat de cgroup. Consulteu la unitat en lloc d’això, fent servir el nom d’instància que existeix a l’amfitrió i no un exemple d’una guia.

systemctl show [email protected] -p User -p LimitNPROC -p TasksCurrent -p TasksMax -p EffectiveTasksMax
cat /proc/$(systemctl show -p MainPID --value [email protected])/limits | grep -i processes

Dins d’un contenidor la resposta necessita dues lectures més, perquè un valor intern d’infinity només descriu la visió del convidat. Demaneu al propietari de l’amfitrió el sostre de pids propi del contenidor i confirmeu si el gestor de serveis intern pot delegar aquest controlador. Una unitat imbricada no pot sostenir un pressupost que el seu cgroup pare no va concedir mai.

Dimensioneu la correcció i demostreu-la sota càrrega

Trieu un número a partir de la càrrega de treball, no del text de l’error. Compteu els processos que el dimoni inicia per client connectat o per invocació d’auxiliar, multipliqueu per la concurrència que es preveu que suporti el desplegament, afegiu un marge per a sessions administratives i després compareu aquesta xifra amb els dos valors efectius. Una substitució local de tipus drop-in manté el canvi revisable i sobreviu a les actualitzacions de paquets, mentre que editar un fitxer d’unitat lliurat amaga la modificació fins que la propera actualització el substitueix. Escriviu l’aritmètica al costat de la substitució, perquè la propera persona que la pugi o la baixi necessita les suposicions, no el número final.

Els canvis de pressupost s’apliquen en l’execució, així que una recàrrega sola no redimensiona els processos que ja s’executen. Reinicieu la unitat pel seu cicle de vida normal, acceptant la interrupció de la sessió, i torneu a llegir els comptadors a la instància nova.

sudo systemctl daemon-reload
sudo systemctl restart [email protected]
systemctl show [email protected] -p TasksCurrent -p EffectiveTasksMax
sudo journalctl -u [email protected] -b --no-pager | tail -n 20

El que demostra la reparació és una unitat reiniciada el recompte de tasques de la qual queda per sota dels dos sostres mentre porta la càrrega prevista, més un journal que ja no informa d’esgotament de tasques o de bifurcacions a la mateixa etapa. Guardeu els números d’abans i després amb el canvi perquè la propera investigació comenci amb un mesurament i no amb el mateix consell. Si el recompte encara arriba al sostre, l’aritmètica era errònia i no pas el límit massa petit per casualitat, i aquesta diferència val la pena conèixer-la abans del proper reinici.

Articles relacionats