Een mislukte start van OpenVPN komt vaak als een klacht over resources plus een goedbedoelde suggestie om een limiet te verhogen, en die suggestie werkt maar ongeveer de helft van de keren. Achter die fouten zitten twee onafhankelijke tellers. De ene is een kernellimiet op het aantal taken dat een echte gebruikers-ID bezit, en die wordt geërfd wanneer het proces wordt uitgevoerd. De andere is een cgroup-budget dat de servicemanager toepast op een unit en alles wat die fork. Het lezen van de effectieve waarde van elk, voor de unit die echt draait, kost minder dan een gok.

Twee tellers, twee vragen

LimitNPROC is RLIMIT_NPROC onder een systemd-naam, en de rekeneenheid is de echte gebruikers-ID. Elk proces dat die gebruiker bezit telt mee in hetzelfde totaal, inclusief werk dat door andere units, door een inlogsessie of door een scheduler-taak is gestart. Het limiet is dus geen plafond per dienst, zelfs niet als het binnen een service-unit is ingesteld, en een dienst die per client een helper fork, concurreert met alles wat onder dat account draait. Een drukke cron-taak onder dezelfde gebruiker kan een VPN-unit over een lijn duwen die hij alleen nooit overschreed.

TasksMax heeft een andere eigenaar: de pids-controller op de cgroup van de unit, die taken telt in plaats van processen. Threads zijn taken, dus een daemon die er eenthreadig uitziet maar een workerpool heeft, kan een budget verbruiken dat op het eerste gezicht veel groter lijkt dan zijn procesaantal. EffectiveTasksMax rapporteert wat de cgroup-hiërarchie werkelijk toestaat nadat de ouderslices hun zegje hebben gedaan.

Waarom de root-uitzondering het antwoord verandert

De kernel past RLIMIT_NPROC niet toe op een proces dat CAP_SYS_RESOURCE of CAP_SYS_ADMIN draagt, waardoor een unit die als root draait zonder privileges af te staan, in de praktijk onbeperkt is door die instelling. Deze ene uitzondering verklaart de tegenstrijdige adviezen die mensen uitwisselen: LimitNPROC verhogen repareert een uitrol die privileges afstond en doet helemaal niets voor een die bevoorrecht bleef. Controleer User= en of de daemon na het starten van identiteit wisselt voordat u die instelling eer of schuld geeft. Een bevoorrechte unit die later overstapt naar een niet-bevoorrecht account, valt op het moment van de overstap weer onder het limiet, wat ook de tijdlijn van de fout lezenswaardig maakt.

De faalfase beperkt het verder. Een weigering tijdens de voorbereiding van de uitvoering, een fork-fout die de daemon zelf meldt en een geweigerde taakcreatie binnen een cgroup leveren verschillende journallijnen op, en slechts één ervan wordt beantwoord met een groter budget.

Lees de effectieve waarden, niet die van de shell

ulimit -u van een interactieve shell beschrijft die shell. Het beschrijft niet wat de servicemanager aan de daemon heeft doorgegeven, en het zegt niets over cgroup-boekhouding. Vraag in plaats daarvan de unit op, met de instantienaam die op de host bestaat en niet een voorbeeld uit een handleiding.

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

Binnen een container heeft het antwoord twee extra uitlezingen nodig, omdat een interne waarde van infinity alleen de weergave van de gast beschrijft. Vraag de eigenaar van de host naar het eigen pids-plafond van de container, en bevestig of de interne servicemanager die controller überhaupt kan delegeren. Een geneste unit kan geen budget houden dat de bovenliggende cgroup nooit heeft gegeven.

Bereken de omvang van de correctie en bewijs die onder belasting

Kies een getal uit de werkbelasting en niet uit de fouttekst. Tel de processen die de daemon per verbonden client of per helperaanroep start, vermenigvuldig met de gelijktijdigheid die de uitrol moet dragen, voeg een marge toe voor beheersessies en vergelijk dat getal dan met de twee effectieve waarden. Een lokale drop-in-overschrijving houdt de wijziging controleerbaar en overleeft pakketupdates, terwijl het bewerken van een meegeleverd unitbestand de wijziging verbergt tot de volgende update het vervangt. Schrijf de berekening naast de overschrijving, want de volgende persoon die hem verhoogt of verlaagt heeft de aannames nodig, niet het eindgetal.

Budgetwijzigingen worden bij uitvoering toegepast, dus een herlaadactie alleen verandert de omvang van al draaiende processen niet. Herstart de unit via de normale levenscyclus, accepteer de onderbreking van de sessie, en lees de tellers opnieuw op de nieuwe instantie.

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

Wat de reparatie bewijst, is een herstarte unit waarvan het taakaantal onder beide plafonds blijft terwijl hij de bedoelde belasting draagt, plus een journal die in dezelfde fase geen taak- of fork-uitputting meer meldt. Bewaar de cijfers voor en na bij de wijziging, zodat het volgende onderzoek begint bij een meting en niet bij hetzelfde advies. Als het aantal het plafond nog steeds haalt, was de berekening fout en niet de limiet toevallig te klein, en dat verschil is de moeite waard om te kennen voor de volgende herstart.

Gerelateerde artikelen