RE:NODE

VDS14 წუთის საკითხავი

Linux-ის swap და OOM killer: რა დააყენო და რატომ

რისთვის არის swap სინამდვილეში, რამდენი მისცე VDS-ს, რას ცვლის swappiness, როგორ ირჩევს OOM killer მსხვერპლს და როგორ წაიკითხო kernel-ის ლოგი.

0 მკითხველი

Swap დამატებითი მეხსიერება არ არის. ეს ადგილია, სადაც kernel ათავსებს გვერდებს, რომლებსაც, მისი აზრით, არ იყენებ, რათა მათ მიერ დაკავებული მეხსიერება სხვა რამეს მოხმარდეს. როცა მუშაობს, ვერც ამჩნევ. როცა მანქანას მეხსიერება ნამდვილად ამოეწურება, swap არ გიხსნის; ის მხოლოდ იმ მომენტს აგვიანებს, როცა ამას გაიგებ, და პროცესს, რომელიც მოკვდება, kernel ირჩევს და არა შენ.

პატარა სერვერებზე ორი რამ არასწორდება. პირველი: swap საერთოდ არ არის და out-of-memory killer გაფრთხილების გარეშე მოდის. მეორე: swap ბევრია და დატვირთვა მთელ მეხსიერებას ეხება, რის გამოც სწრაფი მანქანა გამოუსადეგარი ხდება და არაფერი თითქოს არ ჩამოვარდნილა. ეს პოსტი განიხილავს, რამდენი swap მისცე VDS-ს, რომელი პარამეტრებია რეალური, როგორ წყვეტს OOM killer და როგორ წაიკითხო ხაზი, რომელსაც ის ლოგში ტოვებს, რომ სწორი რამ გამოასწორო.

რისთვის არის swap სინამდვილეში#

Linux გამოყენებულ მეხსიერებას ორ სახეობად ყოფს. Page cache ფაილზე დაფუძნებულია: დისკზე არსებული რაღაცების ასლები, რომლებიც მეხსიერებაში ინახება, რადგან მათი ხელახლა წაკითხვა უფასოა. მისი მოშორება ნებისმიერ მომენტში შეიძლება, ამიტომ ჯანმრთელ სერვერზე free -h თითქმის თავისუფალ მეხსიერებას არ აჩვენებს და ეს პრობლემა არ არის. ანონიმური მეხსიერება ყველაფერი დანარჩენია: heap-ები, stack-ები, შენი პროცესების რეალური სამუშაო მონაცემები. ის ფაილზე დაფუძნებული არ არის, ამიტომ მისი უბრალოდ მოშორება არ შეიძლება. თუ kernel-ს მისი დაბრუნება უნდა, სადმე უნდა გადაიტანოს, და ეს "სადმე" swap-ია.

ამრიგად, swap ერთ კონკრეტულ რამეს გაძლევს: ცივი ანონიმური მეხსიერების გამოძევების უნარს. ეს უფრო მნიშვნელოვანია, ვიდრე ჟღერს. დიდხანს მომუშავე სერვერზე გროვდება მეხსიერება, რომელიც გამოიყოფა და მერე აღარასოდეს შეეხებიან - ინიციალიზაციის buffer-ები, ბიბლიოთეკა, რომელიც ისეთი ფუნქციისთვის ჩაიტვირთა, რომელსაც არავინ იყენებს, ლოგირების გზა, რომელიც გაშვებისას ერთხელ გაიარეს. მანქანაზე swap-ის გარეშე ყოველი ბაიტი ამისა თვეების განმავლობაში RAM-ში ზის. მცირე swap-ით kernel მას ჩუმად გადაიტანს და ადგილს page cache-ისთვის გამოიყენებს, დისკის წაკითხვა კი უფრო სწრაფი ხდება.

Swap-ი, რასაც არ გაძლევს, ტევადობაა. თუ შენს პროცესებს ნამდვილად 10 GB ცოცხალი სამუშაო ნაკრები სჭირდება 8 GB-იან მანქანაზე, swap სწრაფ out-of-memory წარუმატებლობას ნელ, დამქანცველ წარუმატებლობად აქცევს. ეს ჩვეულებრივ უარესია, რადგან ავარია თვალშისაცემია, მანქანა, რომელიც სიჩქარის მეათედზე მუშაობს, - არა.

სიტუაციაSwap-ის გარეშე2 GB swap-ით
ცივი გვერდები გაშვებიდანსამუდამოდ RAM-ში რჩებაგამოიდევნება, RAM cache-ს ხმარდება
მოკლე გამოყოფის ნახტომიOOM killშეიწოვება, მცირე შენელება
სამუშაო ნაკრები RAM-ზე დიდიასწრაფი OOM killThrashing, შემდეგ მაინც OOM kill
მეხსიერების გაჟონვა დღეების განმავლობაშიKill წინასწარ ცნობილ მომენტშიKill მოგვიანებით, საათების ნელი მუშაობის შემდეგ

რამდენი swap და როგორ დაამატო#

RAM-ზე ორჯერ მეტის ძველი წესი ჰიბერნაციისა და 256 MB-იანი მანქანების ეპოქიდან მოდის. სერვერისთვის, რომელიც არასოდეს იძინებს, გამოსადეგი swap-ის რაოდენობა მცირეა და დაახლოებით ფიქსირებული.

RAMSwapდასაბუთება
1-2 GB1-2 GBრეალური მარაგი ამ ზომის მანქანაზე
4-8 GB2 GBსაკმარისია ცივი გვერდების გამოსაძევებლად, არასაკმარისი ხანგრძლივი thrashing-ისთვის
16-24 GB2-4 GBიგივე საქმე; მეტი მხოლოდ გარდაუვალს გადადებდა
მონაცემთა ბაზის ან JVM დატვირთვა1-2 GBგანზრახ ძალიან მცირე, რომ ზომის შეცდომა არ დამალოს

შეამოწმე, რა გაქვს უკვე. ბევრ VDS image-ს swap საერთოდ არ აქვს.

bash
$ swapon --show$ free -h$ cat /proc/swaps

Swap ფაილი ნებისმიერ თანამედროვე kernel-ზე ისეთივე სწრაფია, როგორც swap-ის დანაყოფი, და უსასრულოდ უფრო ადვილი ზომაში შესაცვლელია, ამიტომ ფაილი გამოიყენე:

bash
$ fallocate -l 2G /swapfile$ chmod 600 /swapfile$ mkswap /swapfile$ swapon /swapfile$ swapon --show

თუ fallocate ისეთ ფაილს გააკეთებს, რომელსაც kernel არ იყენებს (ეს ზოგიერთ ფაილურ სისტემაზე ხდება), ჩაწერე ნელი გზით dd if=/dev/zero of=/swapfile bs=1M count=2048-ით და გაიმეორე mkswap-იდან. შემდეგ გადატვირთვაზე გადარჩენა უზრუნველყავი:

/etc/fstab
/swapfile none swap sw 0 0

მოგვიანებით მისი მოსაშორებლად: swapoff /swapfile, შემდეგ ფაილი და fstab-ის ხაზი წაშალე. swapoff-ს ჯერ ყველაფერი RAM-ში უნდა დაუბრუნოს, ამიტომ ის ვერ შესრულდება, თუ საკმარისი თავისუფალი მეხსიერება არ არის, და დატვირთულ მანქანაზე გარკვეული დრო შეიძლება დასჭირდეს.

Swappiness და პარამეტრი, რომელსაც ხალხი პირიქით ესმით#

vm.swappiness არის რიცხვი 0-დან 100-მდე, რომელიც ადგენს, რამდენად ურჩევნია kernel-ს ანონიმური გვერდების გამოძევება page cache-ის მოცილებას, როცა მეხსიერების დაბრუნება სჭირდება. თითქმის ყველა დისტრიბუციაზე ნაგულისხმევია 60. Kernel 5.8-იდან მაქსიმუმი 200-ია, რაც საშუალებას გაძლევს გამოხატო უპირატესობა swap-ისთვის cache-ის დაბრუნებასთან შედარებით და არა უბრალოდ ბალანსი.

გავრცელებული გაუგებრობა ისაა, თითქოს ეს ბარიერია: "swap-ი, როცა მეხსიერება 60%-ით სავსეა". ასე არ არის. ეს ფარდობითი უპირატესობაა, რომელიც მხოლოდ მაშინ მოქმედებს, როცა kernel უკვე აბრუნებს მეხსიერებას. მანქანა, რომელსაც ბევრი თავისუფალი მეხსიერება აქვს, swappiness-ის არცერთი მნიშვნელობით არ დაიწყებს swap-ირებას.

bash
$ cat /proc/sys/vm/swappiness60$ sysctl -w vm.swappiness=10          # გადატვირთვამდე
/etc/sysctl.d/99-memory.conf
vm.swappiness = 10vm.vfs_cache_pressure = 50

გამოიყენე sysctl --system-ით. 10 გონივრული მნიშვნელობაა სერვერისთვის, რომელიც ერთ-ორ დაყოვნებაზე მგრძნობიარე რამეს უშვებს: swap არსებობს, ცივი გვერდები მაინც გამოიდევნება, მაგრამ kernel ჯერ page cache-ს მიმართავს. 0-ზე დაყენება swap-ს არ ჭრის. Kernel 3.5-იდან ეს ნიშნავს "ნუ swap-ავ, თუ სხვა შემთხვევაში OOM არ მოგვიწევს", რაც კანონიერი პარამეტრია მონაცემთა ბაზის ჰოსტისთვის და ცუდი ზოგადი დანიშნულების მანქანისთვის, რადგან კარგავ ცივი გვერდების გამოძევებას, რაც მთელი აზრი იყო.

vm.vfs_cache_pressure აკონტროლებს, რამდენად აქტიურად აბრუნებს kernel დირექტორიის ჩანაწერებისა და inode-ების cache-ს. ნაგულისხმევი 100 ნეიტრალურია; 50-მდე დაწევა ფაილური სისტემის მეტამონაცემებს მეხსიერებაში უფრო დიდხანს ინახავს, რაც ბევრი პატარა ფაილის მქონე სერვერს ეხმარება. ეს მეორეხარისხოვანი პარამეტრია და მიზეზის გარეშე არ უნდა შეეხო.

ის, რაც ცოდნას იმსახურებს და თითქმის არასოდეს იმსახურებს შეცვლას, vm.overcommit_memory-ა. ნაგულისხმევი 0 kernel-ს აძლევს უფლებას, მიიღოს იმაზე დიდი გამოყოფები, ვიდრე მეხსიერება აქვს, გონივრული ვარაუდით, რომ პროგრამების უმეტესობა უფრო მეტს ითხოვს, ვიდრე იყენებს. 2-ზე დაყენება გამოყოფას მკაცრად ითვლის RAM-პლუს-swap-ის მიმართ, გამრავლებულს vm.overcommit_ratio-ზე, რის გამოც malloc პატიოსნად ვარდება და OOM killer მოგვიანებით არ ირთვება. ეს ასევე არღვევს ბევრ პროგრამას, რომელიც ვარაუდობს, რომ შეუძლია ზედმეტი გამოყოფა, JVM-სა და Redis-ს ჩათვლით, ამიტომ თუ კონკრეტული მიზეზი არ გაქვს, არ შეეხო.

OOM killer და როგორ ირჩევს ის#

როცა kernel-ს გამოყოფის დაკმაყოფილება არ შეუძლია და არაფრის დაბრუნება არ შეუძლია, ის out-of-memory killer-ს იძახებს. ეს ავარია არ არის. ეს შეგნებული გადაწყვეტილებაა, რომ ერთი პროცესი SIGKILL-ით შეწყდეს, რათა მანქანა გადარჩეს.

მსხვერპლი ქულით ირჩევა. ყველა პროცესს აქვს, ის ჩანს /proc/<pid>/oom_score-ში და ძირითადად გამომდინარეობს იმით, თუ მთლიანის რა ნაწილს იყენებს მეხსიერებიდან. ჩვეულებრივ, ყველაზე დიდი მომხმარებელი ირჩევა, ამიტომ OOM killer ასე საიმედოდ კლავს ზუსტად იმას, რაც გენანებოდა: სერვერზე ყველაზე დიდი პროცესი შენი მონაცემთა ბაზა ან გეიმ სერვერია და არა გაჟონილი cron ამოცანა, რომელმაც მანქანა ზღვარზე გადაიყვანა.

ამ გადაწყვეტილებაზე შეგიძლია გავლენა მოახდინო /proc/<pid>/oom_score_adj-ით, რომელიც -1000-დან 1000-მდე მერყეობს და ქულას ემატება. -1000 პროცესს ფაქტობრივად გამორიცხავს. 1000 მას მოხალისედ სთავაზობს.

არსებობს ორი განსხვავებული მოვლენა, რომელსაც ორივეს OOM ჰქვია, და მათი გარჩევა აქ ყველაზე სასარგებლო დიაგნოსტიკური უნარია:

  • გლობალური OOM. მთელ მანქანას ამოეწურა. ყველაფერი რისკის ქვეშაა, kernel მსხვერპლს სისტემაში ნებისმიერ ადგილას ირჩევს, ხოლო ლოგის ხაზში წერია constraint=CONSTRAINT_NONE და global_oom.
  • cgroup OOM. ერთმა საკონტროლო ჯგუფმა საკუთარ ლიმიტს მიაღწია, მაშინ როცა მანქანას ჯერ კიდევ აქვს თავისუფალი მეხსიერება. კანდიდატები მხოლოდ ამ ჯგუფის შიგნით მყოფი პროცესებია. ლოგის ხაზი ასახელებს task_memcg გზას. სწორედ ეს ემართება container-ს და ნებისმიერ systemd unit-ს, რომელსაც MemoryMax= აქვს.

ეს განსხვავება წყვეტს გამოსწორებას. გლობალური OOM ნიშნავს: იყიდე მეტი მეხსიერება ან გამოიყენე ნაკლები. cgroup OOM ნიშნავს, რომ ერთმა სერვისმა გადააჭარბა ლიმიტს, რომელიც შენ ან შენმა ჰოსტმა დააყენა, ხოლო დანარჩენ მანქანას პრობლემა არ ჰქონია.

მკვლელობის წაკითხვა ლოგში#

Kernel სრულ ანგარიშს წერს და მისი წაკითხვა უნდა ისწავლო და არა გადაავლო თვალი.

bash
$ dmesg -T | grep -iE "out of memory|killed process|oom-kill"$ journalctl -k -b | grep -i oom$ journalctl -k --since "1 hour ago" | grep -A20 "Out of memory"

ორი მნიშვნელოვანი ხაზი დაახლოებით ასე გამოიყურება:

code
oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,  global_oom,task_memcg=/system.slice/minecraft.service,task=java,pid=2841,uid=1000Out of memory: Killed process 2841 (java) total-vm:9412304kB, anon-rss:6182940kB,  file-rss:0kB, shmem-rss:0kB, UID:1000 pgtables:13248kB oom_score_adj:0

წაიკითხე anon-rss და არა total-vm. total-vm ვირტუალური მისამართთა სივრცეა, რომელიც JVM-ისა თუ Go პროგრამისთვის ჩვეულებრივ რეალურ გამოყენებაზე რამდენჯერმეა დიდი და თითქმის არაფერს ნიშნავს. anon-rss არის ანონიმური მეხსიერება, რომელსაც პროცესი რეალურად RAM-ში ინახავდა, და სწორედ ეს რიცხვია შესადარებელი შენს ლიმიტთან. მაგალითში Java-ს პროცესი, რომელიც დაახლოებით 5.9 GB-ს ინახავდა, მოკლეს მანქანაზე, რომელმაც მეტი ვერ იპოვა.

ამ ხაზების ზემოთ kernel ბეჭდავს ყველა პროცესის ცხრილს მათი RSS-ით, რაც გეუბნება, სხვა რა იყო იმ დროს რეზიდენტული. სწორედ ამ ცხრილიდან იგებ, რომ ის, რაც მოკვდა, ის არ იყო, რაც გაიზარდა: backup სკრიპტმა, რომელმაც დიდი ფაილი წაიკითხა, ან მეორე სერვისმა, რომელიც ორჯერ გაიზარდა, შეიძლება ყველაზე დიდი პროცესი ზღვარზე გადაიყვანოს და თავად არასოდეს იყოს მსხვერპლი.

თუ OOM-ის შეტყობინებას საერთოდ ვერ პოულობ და სერვისი მაინც გაქრა, ეს kernel არ იყო. შეამოწმე systemctl status unit-ის გამოსვლის კოდისთვის და იხილე რატომ ირთვება გეიმ სერვერი განუწყვეტლივ თავიდან სხვა მიზეზებისთვის, რომლებიც უფრო ხშირია, ვიდრე ადამიანები ფიქრობენ.

იმ პროცესის დაცვა, რომელიც გაინტერესებს#

Kernel-ის არჩევანი შეიძლება გადაიფაროს და systemd ამის სუფთა გზაა.

/etc/systemd/system/minecraft.service
[Service]OOMScoreAdjust=-500MemoryHigh=5GMemoryMax=6GMemorySwapMax=512MOOMPolicy=stop

OOMScoreAdjust გლობალური kill-ის გადაწყვეტილებას ისე ცვლის, რომ kernel-ს სხვა რამ ერჩივნოს. MemoryHigh რბილი ლიმიტია: გადაცილებისას cgroup მძიმე reclaim წნევის ქვეშ ექცევა და ნელდება, მაგრამ არ იკლება. MemoryMax მკაცრი ლიმიტია: გადაცილებისას cgroup საკუთარ OOM kill-ს იღებს, დანარჩენ მანქანას კი არ ეხება. MemorySwapMax ზღუდავს, ამ ლიმიტის რა ნაწილი შეიძლება იყოს swap.

ასლის აღებად ღირსი ნიმუში ისაა, რომ MemoryHigh MemoryMax-ზე ცოტათი დაბლაა, იმ სერვისებზე, რომლებსაც არ ენდობი. რბილი ლიმიტი პროცესს მეხსიერების დაბრუნების შანსს აძლევს, სანამ რამე მოკვდება, ხოლო მკაცრი ლიმიტი ნიშნავს, რომ გაუკონტროლებელი სერვისი თავს მოკლავს და მანქანას არ წაიყოლებს. რედაქტირების შემდეგ გაუშვი daemon-reload და unit ფაილის დანარჩენი ნაწილისთვის იხილე systemd სერვისები შენი აპებისთვის.

Ubuntu-ს ახალი ვერსიები ასევე მოიცავს systemd-oomd-ს, userspace დემონს, რომელიც წნევის შეფერხების ინფორმაციას აკვირდება და cgroup-ს კლავს, სანამ kernel-ს მოუწევს. ის kernel-ის killer-ზე ადრე და უფრო პროგნოზირებადად მოქმედებს და თავის მიზეზებს journalctl -u systemd-oomd-ში წერს. თუ სერვისი Ubuntu 22.04-ზე ან უფრო ახალზე kernel-ის OOM შეტყობინების გარეშე იხოცება, მანამ, სანამ დაასკვნი, რომ თავისით ჩაიშალა, იქ შეამოწმე.

წნევა, რომელზეც ის რეაგირებს, პირდაპირ შეგიძლია დააკვირდე:

bash
$ cat /proc/pressure/memorysome avg10=0.00 avg60=0.13 avg300=0.09 total=4192031full avg10=0.00 avg60=0.04 avg300=0.02 total=1104822

some არის დროის წილი, როცა სულ მცირე ერთი task მეხსიერებას ელოდებოდა; full არის წილი, როცა ყველაფერი ელოდებოდა. full avg60, რომელიც მუდმივად რამდენიმე პროცენტს აღემატება, ნიშნავს, რომ მანქანა ნამდვილ დროს ხარჯავს მეხსიერების დაბრუნებაზე, და ეს free-ს სვეტზე უკეთესი ადრეული გაფრთხილებაა.

Swap, დაყოვნება და JVM#

Swap და garbage collection ცუდი კომბინაციაა და სწორედ აქ ხვდება გეიმ სერვერის ოპერატორების უმეტესობა ამ პრობლემას.

JVM-ის heap ანონიმური მეხსიერებაა, რომელსაც კოლექტორი პერიოდულად გადის. თუ kernel-მა ამ heap-ის ნაწილი swap-ში გადაიტანა, რადგან ცივად გამოიყურებოდა, შემდეგ major collection-ს ყველაფერი გვერდ-გვერდ, საცავის მოწყობილობით უკან უნდა წაიკითხოს. Collection, რომელსაც ჩვეულებრივ 40 მილიწამი სჭირდება, რამდენიმე წამს იკავებს. Minecraft-ის სერვერზე ეს ყველასთვის ჩანს, როგორც გაყინვა, და მეორდება. იგივე ლოგიკა ვრცელდება ნებისმიერ გარემოზე tracing კოლექტორით და ნებისმიერ მონაცემთა ბაზაზე, რომელსაც დიდი პროცესშიდა cache აქვს.

პრაქტიკული წესები:

  • Heap-ის ზომა ისე შეარჩიე, რომ RAM-ში ჩაეტიოს და ადგილი დარჩეს. -Xmx პლუს JVM-ის off-heap ზედნადები პლუს ოპერაციული სისტემა კომფორტულად უნდა იყოს მთლიანზე ქვემოთ. Minecraft-ის JVM flag-ები და Java-ს ვერსიები განმარტავს, რა არის ეს ზედნადები სინამდვილეში, ხოლო რამდენი RAM სჭირდება Minecraft-ის სერვერს ზომის შერჩევას ფარავს.
  • ამ მანქანებზე swappiness დაბალი გქონდეს. vm.swappiness = 10 ან 1.
  • Unit-ის swap-ი MemorySwapMax=-ით შეზღუდე და მარტო swappiness-ს არ ენდო.
  • ნუ დაამატებ swap-ს არასაკმარისი სერვერის გამოსასწორებლად. თუ heap არ ეტევა, პასუხი უფრო დიდი გეგმაა და არა უფრო დიდი swap ფაილი. როდის გააუმჯობესო გეგმა განსხვავების ამოცნობას ფარავს.

იმის სანახავად, არის თუ არა კონკრეტული პროცესი ამჟამად swap-ში:

bash
$ grep VmSwap /proc/2841/statusVmSwap:      412360 kB$ for p in /proc/[0-9]*; do    printf "%s %s\n" "$(grep VmSwap $p/status 2>/dev/null | awk '{print $2}')" \      "$(cat $p/comm 2>/dev/null)"  done | sort -rn | head

თუ პროცესს, რომელიც გაინტერესებს, VmSwap-ში ასობით მეგაბაიტი აქვს, ეს შენი დაყოვნების პრობლემაა, და swapoff -a && swapon -a ყველაფერს მაშინვე დააბრუნებს RAM-ში, თუ ამისთვის თავისუფალი მეხსიერება გაქვს.

Thrashing: როცა swap ყველაფერს აუარესებს#

Thrashing ის არის, როცა სამუშაო ნაკრები არ ეტევა და kernel დროს იმავე გვერდების შიგნით-გარეთ გადაადგილებაში ხარჯავს. სიმპტომი გამორჩეულია, როცა ერთხელ ნახავ: load average მაღალია, CPU ძირითადად უსაქმოა, ყველაფერი ნელია და არაფერი ჩამოვარდნილა.

bash
$ vmstat 1 10$ iostat -x 2          # sysstat პაკეტიდან

vmstat-ში si და so სვეტები წამში swap-ში შემოსული და გასული გვერდებია. ხანდახან პატარა რიცხვები კარგია და ნორმალური. მუდმივი ასეულები ან ათასეულები მაღალ wa-სთან (iowait) CPU-ს სვეტებში - thrashing-ია და ვერანაირი ტიუნინგი მას ვერ გამოასწორებს. მანქანას ნაკლები სამუშაო ან მეტი მეხსიერება სჭირდება.

სწორედ ამიტომ პატარა swap ფაილი თვისებაა და არა კომპრომისი. 2 GB swap-ით გაუკონტროლებელი პროცესი რამდენიმე წუთში OOM killer-ს ხვდება და მანქანა გამოჯანმრთელდება. 16 GB swap-ით ის ჯერ ერთ საათს ბრუნავს, შენი მონიტორინგი ავარიაზე კი არა, დაყოვნებაზე გაფრთხილებს, და ამ საათს ისეთ მანქანაში SSH-ით შესვლას ცდი, რომელიც ისე დაკავებულია, რომ shell-ს ვერ გაძლევს. სერვერის დატვირთვის გრაფიკის კითხვა ამოსაცნობ ფორმებს შეიცავს.

მართულ RE:NODE გეგმაზე ეს მთელი წარუმატებლობის რეჟიმი განზრახ მოხსნილია. ყოველი სერვერი საკუთარ container-შია მკაცრი მეხსიერების ლიმიტით და ლიმიტზე kernel container-ს აჩერებს და ის სუფთად ირთვება ხელახლა და არა swap-ში რჩება. ეს upstream Pterodactyl-ის ნაგულისხმევის საპირისპიროა და კომპრომისია: კარგავ შანსს, რომ მოკლე ნახტომი შეიწოვება, და იძენ სერვერს, რომელიც წამებში დაბრუნდება, იმის ნაცვლად, რომელიც ტექნიკურად მუშაობს და საათის განმავლობაში გამოუსადეგარია. CPU-ც ასევე მუშაობს - მკაცრი შეზღუდვა შენ მიერ ნაყიდ წილამდე, ამიტომ 100%-ზე მყოფი სერვერი ნელია და არა გატეხილი. VDS-ზე ყოველივე ეს შენი გასაწყობია, და ეს ზუსტად ის არის, რასაც ეს პოსტი განიხილავდა. VDS-სა და გეიმ პანელს შორის არჩევანი ორივეს სათანადოდ წონის.

ალტერნატივად პატარა მანქანებზე ღირს zram-ის ხსენება: ის ქმნის შეკუმშულ ბლოკურ მოწყობილობას RAM-ში და swap-ად იყენებს. გვერდები დისკზე წერის ნაცვლად იკუმშება, ჩვეულებრივ მესამედამდე ან ნახევრამდე, ამიტომ swap-ის სარგებლის ნაწილს იღებ საცავის დაყოვნების გარეშე. Debian-სა და Ubuntu-ზე zram-tools პაკეტი მას რამდენიმე ხაზში აწყობს. ის ნამდვილად გამოსადეგია 1-2 GB-იან მანქანაზე და თითქმის უაზროა 8 GB-ზე ზემოთ, სადაც მეხსიერების წნევის რეალური პასუხი მისი ნაკლები გამოყენებაა.

FAQ#

უნდა ჰქონდეს სერვერს swap საერთოდ?

დიახ, მცირე რაოდენობა. ნულოვანი swap ნიშნავს, რომ ცივი ანონიმური გვერდები სამუდამოდ RAM-ში ზის და OOM killer სრულიად გაფრთხილების გარეშე მოდის. ერთი-ორი გიგაბაიტი kernel-ს ადგილს აძლევს გვერდებისთვის, რომლებსაც არავინ ეხება, საკმარისი ოთახის გარეშე, რომ საათით thrashing-ი გაგრძელდეს.

თავიდან აგვაცილებს მეტი swap OOM killer-ს?

მხოლოდ გადადებით. Killer მაშინ ირთვება, როცა kernel-ს არაფრის დაბრუნება არ შეუძლია, და უზარმაზარი swap ფაილი ნიშნავს, რომ ამ წერტილამდე მისვლას ბევრად მეტი დრო სჭირდება, მანქანის სიჩქარის ნაწილზე. თუ OOM-ს რეგულარულად ხვდები, გამოსავალი ნაკლები მეხსიერების გამოყენება ან მეტი RAM-ია.

რას აკეთებს swappiness 0?

ის kernel-ს ეუბნება, თავი აარიდოს ანონიმური მეხსიერების swap-ირებას, სანამ ალტერნატივა OOM kill არ იქნება. ის swap-ს არ ათიშავს და page cache-ის დაბრუნებას არ ათიშავს. ზოგადი სერვერისთვის გამოიყენე 10; 0 ან 1 მხოლოდ მონაცემთა ბაზისთვის ან JVM-ისთვის გამოყოფილ ჰოსტზე.

რატომ მოკლა OOM killer ჩემი მონაცემთა ბაზა იმის ნაცვლად, რაც გაჟონა?

იმიტომ, რომ ის მეხსიერების გამოყენებით აფასებს, ხოლო შენი მონაცემთა ბაზა მანქანაზე ყველაზე დიდი პროცესი იყო. გაჟონვამ სისტემა ზღვარზე გადაიყვანა; ქულამ მსხვერპლი აირჩია. გამოიყენე OOMScoreAdjust იმ სერვისზე, რომლის დაცვაც გინდა, და MemoryMax იმაზე, ვისაც არ ენდობი.

როგორ გავიგო, container-მა ამოწურა თუ მთელმა მანქანამ?

წაიკითხე oom-kill: ხაზი dmesg-ში. constraint=CONSTRAINT_NONE global_oom-თან ერთად ნიშნავს მანქანას. task_memcg გზა, რომელიც კონკრეტულ slice-ზე ან container-ზე მიუთითებს, global_oom-ის გარეშე, ნიშნავს, რომ ამ cgroup-მა საკუთარ ლიმიტს მიაღწია, ჰოსტი კი კარგად იყო.

საკმარისად სწრაფია NVMe-ზე swap, რომ არ აქვს მნიშვნელობა?

ის ბევრად უკეთესია, ვიდრე მბრუნავ დისკებზე იყო, და მაინც დაახლოებით ათასჯერ უფრო ნელია, ვიდრე RAM. NVMe swap-ს კატასტროფულიდან უბრალოდ ცუდად აქცევს. ის swap-ს მეხსიერების შემცვლელად არ აქცევს და garbage collector-ს არ იხსნის, რომელსაც მთელი heap უკან უნდა ამოიღოს.


კომენტარები

სრულიად ანონიმურად: ანგარიშის, ელფოსტის და cookie-ის გარეშე. ინახება მხოლოდ სახელი, ტექსტი და დრო - სხვა არაფერი. ბმულების რაოდენობა ლიმიტირებულია.

0/2000