Μια αποτυχημένη εκκίνηση του OpenVPN φτάνει συχνά ως παράπονο για πόρους μαζί με μια καλοπροαίρετη πρόταση να ανέβει κάποιο όριο, και η πρόταση δουλεύει μόνο περίπου τις μισές φορές. Πίσω από αυτές τις αποτυχίες στέκονται δύο άσχετοι μετρητές. Ο ένας είναι ένα όριο του πυρήνα στον αριθμό των εργασιών που ανήκουν σε ένα πραγματικό αναγνωριστικό χρήστη, και κληρονομείται όταν εκτελείται η διεργασία. Ο άλλος είναι ένας προϋπολογισμός cgroup που ο διαχειριστής υπηρεσιών εφαρμόζει σε μια μονάδα και σε ό,τι αυτή διακλαδίζει. Το να διαβάσετε την πραγματική τιμή καθενός, για τη μονάδα που τρέχει όντως, κοστίζει λιγότερο από μια εικασία.

Δύο μετρητές, δύο ερωτήματα

Το LimitNPROC είναι το RLIMIT_NPROC κάτω από ένα όνομα του systemd, και η λογιστική του μονάδα είναι το πραγματικό αναγνωριστικό χρήστη. Κάθε διεργασία που κατέχει αυτός ο χρήστης μετρά στο ίδιο σύνολο, μαζί με εργασία που ξεκίνησαν άλλες μονάδες, μια συνεδρία σύνδεσης ή μια εργασία χρονοπρογραμματιστή. Το όριο επομένως δεν είναι ανώτατο όριο ανά υπηρεσία ακόμη και όταν ορίζεται μέσα σε μια μονάδα υπηρεσίας, και μια υπηρεσία που διακλαδίζει έναν βοηθό για κάθε πελάτη ανταγωνίζεται ό,τι άλλο τρέχει κάτω από αυτόν τον λογαριασμό. Μια πολυάσχολη εργασία cron κάτω από τον ίδιο χρήστη μπορεί να σπρώξει μια μονάδα VPN πέρα από μια γραμμή που η ίδια δεν πέρασε ποτέ.

Το TasksMax έχει άλλον ιδιοκτήτη: τον ελεγκτή pids στο cgroup της μονάδας, που μετρά εργασίες και όχι διεργασίες. Τα νήματα είναι εργασίες, οπότε ένας δαίμονας που μοιάζει μονονηματικός αλλά έχει δεξαμενή εργατών μπορεί να καταναλώσει προϋπολογισμό που με μια ματιά φαίνεται πολύ μεγαλύτερος από τον αριθμό των διεργασιών του. Το EffectiveTasksMax αναφέρει τι επιτρέπει πραγματικά η ιεραρχία cgroup αφού πουν τη γνώμη τους τα γονικά slices.

Γιατί η εξαίρεση του root αλλάζει την απάντηση

Ο πυρήνας δεν εφαρμόζει το RLIMIT_NPROC σε διεργασία που φέρει το CAP_SYS_RESOURCE ή το CAP_SYS_ADMIN, γι' αυτό μια μονάδα που τρέχει ως root χωρίς να εγκαταλείψει προνόμια είναι πρακτικά απεριόριστη από αυτή τη ρύθμιση. Αυτή η μοναδική εξαίρεση εξηγεί τις αντιφατικές συμβουλές που ανταλλάσσουν οι άνθρωποι: το ανέβασμα του LimitNPROC διορθώνει μια εγκατάσταση που εγκατέλειψε προνόμια και δεν κάνει απολύτως τίποτα για μια που έμεινε προνομιούχα. Ελέγξτε το User= και αν ο δαίμονας αλλάζει ταυτότητα μετά την εκκίνηση πριν χρεώσετε ή επιρρίψετε ευθύνη σε αυτή τη ρύθμιση. Μια προνομιούχα μονάδα που αργότερα περνά σε μη προνομιούχο λογαριασμό πέφτει ξανά κάτω από το όριο τη στιγμή της μετάβασης, και αυτό κάνει και το χρονοδιάγραμμα της αποτυχίας άξιο ανάγνωσης.

Το στάδιο της αποτυχίας το περιορίζει περαιτέρω. Μια άρνηση κατά την προετοιμασία εκτέλεσης, ένα σφάλμα διακλάδωσης που αναφέρει ο ίδιος ο δαίμονας και μια απορριφθείσα δημιουργία εργασίας μέσα σε cgroup παράγουν διαφορετικές γραμμές journal, και μόνο μία από αυτές απαντιέται από μεγαλύτερο προϋπολογισμό.

Διαβάστε τις πραγματικές τιμές, όχι του κελύφους

Το ulimit -u ενός διαδραστικού κελύφους περιγράφει αυτό το κέλυφος. Δεν περιγράφει τι πέρασε ο διαχειριστής υπηρεσιών στον δαίμονα, και δεν λέει τίποτα για τη λογιστική του cgroup. Ρωτήστε αντ' αυτού τη μονάδα, χρησιμοποιώντας το όνομα στιγμιότυπου που υπάρχει στον κεντρικό υπολογιστή και όχι ένα παράδειγμα από έναν οδηγό.

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

Μέσα σε ένα κοντέινερ η απάντηση χρειάζεται δύο ακόμη αναγνώσεις, γιατί μια εσωτερική τιμή του infinity περιγράφει μόνο την οπτική του επισκέπτη. Ζητήστε από τον ιδιοκτήτη του κεντρικού υπολογιστή το δικό του ανώτατο όριο pids για το κοντέινερ, και επιβεβαιώστε αν ο εσωτερικός διαχειριστής υπηρεσιών μπορεί να εκχωρήσει καθόλου αυτόν τον ελεγκτή. Μια ένθετη μονάδα δεν μπορεί να κρατήσει προϋπολογισμό που το γονικό της cgroup δεν παραχώρησε ποτέ.

Υπολογίστε το μέγεθος της διόρθωσης και αποδείξτε το υπό φόρτο

Διαλέξτε έναν αριθμό από τον φόρτο εργασίας και όχι από το κείμενο του σφάλματος. Μετρήστε τις διεργασίες που ξεκινά ο δαίμονας ανά συνδεδεμένο πελάτη ή ανά κλήση βοηθού, πολλαπλασιάστε με τη συγχρονικότητα που αναμένεται να σηκώσει η εγκατάσταση, προσθέστε ένα περιθώριο για διοικητικές συνεδρίες και μετά συγκρίνετε αυτόν τον αριθμό με τις δύο πραγματικές τιμές. Μια τοπική παράκαμψη drop-in κρατά την αλλαγή ελέγξιμη και επιβιώνει από αναβαθμίσεις πακέτων, ενώ η επεξεργασία ενός αρχείου μονάδας που παραδίδεται κρύβει την αλλαγή ώσπου να την αντικαταστήσει η επόμενη ενημέρωση. Γράψτε την αριθμητική δίπλα στην παράκαμψη, γιατί ο επόμενος που θα την ανεβάσει ή θα τη χαμηλώσει χρειάζεται τις παραδοχές και όχι τον τελικό αριθμό.

Οι αλλαγές προϋπολογισμού εφαρμόζονται κατά την εκτέλεση, οπότε μια απλή επαναφόρτωση δεν αλλάζει το μέγεθος διεργασιών που τρέχουν ήδη. Επανεκκινήστε τη μονάδα μέσω του κανονικού κύκλου ζωής της, αποδεχόμενοι τη διακοπή της συνεδρίας, και διαβάστε ξανά τους μετρητές στο νέο στιγμιότυπο.

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

Αυτό που αποδεικνύει την επισκευή είναι μια επανεκκινημένη μονάδα της οποίας το πλήθος εργασιών μένει κάτω από τα δύο ανώτατα όρια ενώ φέρει το προβλεπόμενο φόρτο, μαζί με ένα journal που δεν αναφέρει πια εξάντληση εργασιών ή διακλάδωσης στο ίδιο στάδιο. Κρατήστε τους αριθμούς πριν και μετά μαζί με την αλλαγή ώστε η επόμενη έρευνα να ξεκινά από μια μέτρηση και όχι από την ίδια συμβουλή. Αν το πλήθος φτάνει ακόμη το ανώτατο όριο, η αριθμητική ήταν λάθος και όχι το όριο τυχαία πολύ μικρό, και αυτή η διαφορά αξίζει να τη γνωρίζετε πριν από την επόμενη επανεκκίνηση.

Σχετικά άρθρα