„დისკის შეცდომები“ OOM აღმოჩნდა: როგორ დაკარგეს Longhorn-ის ტომებმა ბექენდი
EIO, read-only ext4, დაზიანებული MySQL datadir და დალუქული Vault მომაკვდავ დისკს ჰგავდა. ჰოსტის dmesg-მა მთელი ნოდის OOM აჩვენა, რომელმაც პირველად Longhorn-ის instance-manager მოკლა.
Optimacros-ში self-managed Kubernetes კლასტერის ერთმა ნოდამ „ციმციმი“ დაიწყო. მასზე მყოფმა პოდებმა EIO მიიღეს, ext4 read-only-ში გადამონტაჟდა, MySQL-ის datadir დაზიანდა, Vault-ის ერთი პირი დაილუქა, kubelet კი მცირე ხნით NotReady-ში გადავიდა. შემდეგ ყველაფერი ისევ ნორმალურად გამოიყურებოდა: ნოდა Ready იყო, Longhorn ყველა ტომს ჯანმრთელად აჩვენებდა.
მაცდური დასკვნა
შეტანა-გამოტანის შეცდომები ბლოკურ მოწყობილობებზე, read-only ფაილური სისტემა, დაზიანებული datadir-ის მქონე ბაზა — ყველა სიმპტომი საცავზე მიუთითებს. ბუნებრივი შემდეგი ნაბიჯებია „დისკის შეცვლა“ ან „ბირთვის დაპატჩვა“. ორივე დროს წაიღებდა და არაფერს გამოასწორებდა.
შემაჩერა იმან, რომ kubectl მოვლენას ვერ ხსნიდა. „ახლა ჯანმრთელია“ იმის ახსნა არ არის, რაც 03:00-ზე მოხდა, ამიტომ ჰოსტზე გადავედი.
რა თქვა dmesg-მა
ნოდაზე პრივილეგირებულმა debug პოდმა (kubectl debug node/... --profile=sysadmin, chroot ჰოსტში) და dmesg-ზე grep-მა მოვლენების რეალური თანმიმდევრობა მოგვცა:
global_oom, constraint=CONSTRAINT_NONE. მთელ ნოდას მეხსიერება ამოეწურა. OOM killer-მა ბევრი პროცესი მოკლა, მათ შორისlonghorn-instance-managerდა ნოდის CSI დრაივერი.- დაახლოებით ორი წუთის შემდეგ:
EXT4-fs error ... unable to read itable blockდაJBD2: I/O error ... journal superblockLonghorn-ის ბლოკურ მოწყობილობებზე.
თანმიმდევრობა მნიშვნელოვანია. Instance-manager ამ ნოდაზე Longhorn-ის ყველა ტომის ბლოკური ბექენდია. მოკალი ის — და ყველა ამ ტომზე დაუსრულებელი შეტანა-გამოტანა EIO-ს დააბრუნებს; ext4 read-only-ში გადამონტაჟდება; ბაზა, რომელიც იმ წამს წერდა, დაზიანდება. დისკის შეცდომები OOM-ის სიმპტომი იყო და არა დისკის მწყობრიდან გამოსვლა.
მთავარი დეტალია CONSTRAINT_NONE. ეს ნიშნავს, რომ OOM მთელ ნოდაზე იყო და არა ერთ კონტეინერზე, რომელიც საკუთარ ლიმიტს მიებჯინა. ანუ ეს ტევადობისა და QoS-ის პრობლემაა.
რატომ გახდა საცავის ბექენდი მსხვერპლი
ორი რამ დაემთხვა.
- ბევრი პოდი
BestEffort-ად მუშაობდა, მეხსიერების მოთხოვნების გარეშე. დამგეგმავი მხოლოდ requests-ს ითვლის, ამიტომ ნოდა მის რეალურ RAM-ზე მეტად ჩატვირთა. - Instance-manager
Burstable-ად მუშაობდა მეხსიერების მოთხოვნის გარეშე. მასlonghorn-criticalPriorityClass ჰქონდა, მაგრამ PriorityClass დაგეგმვასა და განდევნაზე მოქმედებს და არა ბირთვის OOM score-ზე.oom_score_adj-ის შემცირება მხოლოდ მეხსიერების მოთხოვნას შეუძლია.
ამიტომ, როცა მეხსიერება ამოიწურა, ბირთვმა დაინახა დიდი, დაბალპრიორიტეტული გარეგნობის პროცესი და მოკლა ზუსტად ის, რაზეც ნოდის ყველა ტომი იყო დამოკიდებული.
გამოსავალი
- Instance-manager-ს მეხსიერების მოთხოვნა მივეცით, იდეალურად ლიმიტის ტოლი, რომ
Guaranteedგამხდარიყო, Longhorn-ის guaranteed instance-manager პარამეტრებით. - რეალურ დატვირთვებს
BestEffortმოვუხსენით: მეხსიერების მოთხოვნები ფაქტობრივი მოხმარებით დავაყენეთ, რომ დამგეგმავმა ნოდების გადატვირთვა შეწყვიტოს.
Instance-manager-ის რესურსების შეცვლა მას გადატვირთავს და ამ ნოდის ტომებს მცირე ხნით გამოაერთებს, ამიტომ ამას ნოდა-ნოდა ფანჯარაში ვაკეთებდი. თავად დიაგნოსტიკა read-only იყო — უბრალოდ არ დაგავიწყდეთ შემდეგ node-debugger პოდის წაშლა.
დასკვნები
- Longhorn-ის მოწყობილობებზე
EIOinstance-manager-ის სიკვდილისთანავე სწორედ ამ მარცხის ხელწერაა. დისკის შეკვეთამდე ჰოსტისdmesgწაიკითხეთ. - OOM-ის ხაზში
constraint=CONSTRAINT_NONEნიშნავს, რომ მეხსიერება ნოდას ამოეწურა და არა პოდს. - PriorityClass დაგეგმვას იცავს და არა OOM-ის დროს გადარჩენას. ამისთვის მეხსიერების მოთხოვნებია საჭირო.
BestEffortპოდები უფასო არ არის: ისინი ხარჯავენ მარაგს, რომელსაც დამგეგმავი ვერ ხედავს, ანგარიში კი მას მოსდის, ვისაც ბირთვი მოსაკლავად აირჩევს.