LimitNPROC TasksMax-ის წინააღმდეგ: რას ითვლის OpenVPN-ის ერთეული
LimitNPROC ერთი მომხმარებლის პროცესებს მთელ სისტემაში ითვლის; TasksMax ერთი ერთეულის cgroup-ს ზღუდავს. რომელიმეს აწევამდე წაიკითხეთ ფაქტობრივი მნიშვნელობები.
OpenVPN-ის წარუმატებელი გაშვება ხშირად მოდის რესურსებზე ჩივილისა და ლიმიტის აწევის კეთილგანწყობილი შემოთავაზების სახით, და ეს შემოთავაზება მხოლოდ დაახლოებით ნახევარ შემთხვევაში მუშაობს. ამ წარუმატებლობების მიღმა ორი დაუკავშირებელი მთვლელი დგას. ერთი არის ბირთვის ლიმიტი რეალური მომხმარებლის ID-ის კუთვნილ ამოცანათა რაოდენობაზე და ის პროცესის გაშვებისას მემკვიდრეობით გადადის. მეორე არის cgroup-ის ბიუჯეტი, რომელსაც სერვისების მმართველი ერთეულზე და ყველაფერზე, რასაც ის ტოტავს, იყენებს. თითოეულის ფაქტობრივი მნიშვნელობის წაკითხვა, იმ ერთეულისთვის, რომელიც ნამდვილად მუშაობს, ვარაუდზე ნაკლები ღირს.
ორი მთვლელი, ორი კითხვა
LimitNPROC არის RLIMIT_NPROC systemd-ის სახელის ქვეშ, და მისი აღრიცხვის ერთეული რეალური მომხმარებლის ID-ია. ამ მომხმარებლის კუთვნილი ყველა პროცესი ერთსა და იმავე ჯამში ითვლება, მათ შორის სხვა ერთეულების, შესვლის სესიის ან დამგეგმავის ამოცანის მიერ დაწყებული სამუშაო. ამიტომ ეს ლიმიტი არ არის სერვისის ცალკე ჭერი, მაშინაც კი, როცა ის სერვისის ერთეულის შიგნით არის დაყენებული, და სერვისი, რომელიც ყოველი კლიენტისთვის დამხმარეს ტოტავს, ეჯიბრება ყველაფერს, რაც ამ ანგარიშის ქვეშ მუშაობს. ერთსა და იმავე მომხმარებლის ქვეშ დაკავებულმა cron-ის ამოცანამ შეიძლება VPN-ის ერთეული გადააჭარბოს იმ ხაზს, რომელიც მან თავად არასოდეს გადაკვეთა.
TasksMax-ს სხვა მფლობელი ჰყავს: pids-ის კონტროლერი ერთეულის cgroup-ზე, რომელიც ამოცანებს ითვლის და არა პროცესებს. ნაკადები ამოცანებია, ამიტომ ერთნაკადიანი შთაბეჭდილების მქონე, მაგრამ მუშათა აუზის მქონე დემონს შეუძლია მოიხმაროს ბიუჯეტი, რომელიც ერთი შეხედვით მის პროცესთა რაოდენობაზე ბევრად დიდი ჩანს. EffectiveTasksMax იტყობინება, თუ რას უშვებს სინამდვილეში cgroup-ის იერარქია მას შემდეგ, რაც მშობელი ნაწილები თავიანთ სათქმელს იტყვიან.
რატომ ცვლის root-ის გამონაკლისი პასუხს
ბირთვი არ იყენებს RLIMIT_NPROC-ს იმ პროცესზე, რომელსაც CAP_SYS_RESOURCE ან CAP_SYS_ADMIN აქვს, ამიტომ უპირატესობების დათმობის გარეშე root-ად მომუშავე ერთეული ამ პარამეტრით პრაქტიკულად უსაზღვროა. ეს ერთადერთი გამონაკლისი ხსნის იმ წინააღმდეგობრივ რჩევებს, რომლებსაც ადამიანები ცვლიან: LimitNPROC-ის აწევა არემონტებს უპირატესობების დათმობილ განლაგებას და საერთოდ არაფერს აკეთებს უპირატესობის შემონახულისთვის. სანამ ამ პარამეტრს დამსახურებას ან ბრალს მიაწერთ, შეამოწმეთ User= და ის, იცვლის თუ არა დემონი იდენტობას გაშვების შემდეგ. უპირატესობის მქონე ერთეული, რომელიც მოგვიანებით უპირატესობის არმქონე ანგარიშზე გადადის, გადასვლის მომენტში ისევ ლიმიტის ქვეშ ექცევა, რაც წარუმატებლობის დროით ხაზსაც საკითხავს ხდის.
წარუმატებლობის ეტაპი კიდევ უფრო ვიწროა. გაშვების მომზადებისას უარი, თავად დემონის მიერ მოხსენებული ტოტვის შეცდომა და cgroup-ის შიგნით უარყოფილი ამოცანის შექმნა სხვადასხვა journal-ის სტრიქონებს იძლევა, და მათგან მხოლოდ ერთს პასუხობს უფრო დიდი ბიუჯეტი.
წაიკითხეთ ფაქტობრივი მნიშვნელობები და არა shell-ის
ინტერაქტიული shell-ის ulimit -u ამავე shell-ს აღწერს. ის არ აღწერს, თუ რა გადასცა სერვისების მმართველმა დემონს და არაფერს ამბობს 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, რომელიც იმავე ეტაპზე აღარ იტყობინება ამოცანების ან ტოტვის ამოწურვაზე. შეინახეთ წინ და შემდეგ რიცხვები ცვლილებასთან ერთად, რომ შემდეგი გამოძიება გაზომვით დაიწყოს და არა იმავე რჩევით. თუ რიცხვი მაინც აღწევს ჭერს, არითმეტიკა იყო მცდარი და არა ლიმიტი შემთხვევით ძალიან მცირე, და ეს სხვაობა შემდეგ გადატვირთვამდე ღირს ცოდნად.