Postgres-ის რეპლიკა 23 საათი pg_rewind-ის ციკლში ტრიალებდა: ხელახლა შექმენით და ნუ შეაკეთებთ
failover-ის შემდეგ CloudNativePG-ის რეპლიკამ rewind ვერ გააკეთა: მისი WAL-სეგმენტები ნულოვანი ზომის იყო, მონაცემთა კატალოგი კი primary-ზე ათჯერ პატარა. 23 საათი ვერავინ შეამჩნია, რადგან ოპერატორის მეტრიკები არ გროვდებოდა.
ჩემს სახლის ლაბორატორიაში ერთი გვერდითი პროექტი მუშაობდა CloudNativePG-ის ორინსტანსიან კლასტერზე: Postgres 16 Longhorn-ის საცავზე, WAL არქივდება ობიექტურ საცავში. ერთ დღეს კლასტერმა შეგვატყობინა „2 ინსტანსი, 1 მზადაა“. რეპლიკის readiness-პრობა HTTP 500-ით უკვე 23 საათი ეცემოდა — თითქმის ცხრა ათასი წარუმატებლობა. Primary მთელი ამ დროის განმავლობაში ჯანმრთელი იყო, ამიტომ აპლიკაცია არც ერთხელ არ გათიშულა. მხოლოდ მაღალი ხელმისაწვდომობა დაიკარგა.
რა თქვა pg_rewind-მა
failover-ის შემდეგ timeline 14-დან 15-ზე გადავიდა და დაქვეითებულ ინსტანსს ახალ timeline-ზე rewind უნდა გაეკეთებინა. ვერ შეძლო:
pg_rewind: servers diverged at WAL location 23/4B000000 on timeline 14
pg_rewind: error: could not read file ".../pg_wal/0000000E000000230000004A": read 0 of 8192
რეპლიკის ლოკალური WAL-სეგმენტები განშტოების წერტილის გარშემო ნულოვანი ზომის იყო, ყველა ინციდენტის მომენტის დროის ნიშნულით. მონაცემთა კატალოგი — 407 MB primary-ზე 4,5 GB-ის წინააღმდეგ. WAL-ის გარეშე rewind შეცდომით სრულდება, instance manager მცდელობას იმეორებს და readiness არასოდეს მწვანდება. სამუდამოდ.
საქმე დისკში არ იყო
პირველი ეჭვმიტანილი საცავი იყო: ამ ჰოსტის ქვეშ დეგრადირებადი SSD დგას. მაგრამ Longhorn-ის ტომი მიერთებული და ჯანმრთელი იყო, ტომის ორივე რეპლიკა მუშაობდა, არაფერი დაცემულა. ამჯერად საცავი უდანაშაულო იყო.
შესაკეთებელი არაფერი იყო
მონაცემთა კატალოგი მოძველებული კი არა — საერთოდ არ იყო. ამიტომ გამოსავალი — რეპლიკის გადაგდება და ოპერატორისთვის primary-დან ახლის შექმნის საშუალების მიცემა:
kubectl -n <ns> delete pvc <replica> --wait=false
kubectl -n <ns> delete pod <replica>
ოპერატორმა ახალი ტომი შექმნა, join-პოდი pg_basebackup-ით გაუშვა, ინსტანსი სტარტზე გაიყვანა, აღდგენის შეთანხმებულ მდგომარეობას მიაღწია და სტრიმინგი დაიწყო. დაახლოებით ოთხი წუთი 4,5 GB-ზე. ამის შემდეგ primary რეპლიკას streaming-რეჟიმში ნულოვანი ლაგით აჩვენებდა.
შემოწმება, რომელმაც კინაღამ მომატყუა
იმაში დასარწმუნებლად, რომ რეპლიკაზე მონაცემები არის, pg_stat_user_tables.n_live_tup-ს შევხედე. ჯამში ნული სტრიქონი იყო. ერთი წამით მომეჩვენა, რომ ბაზა ცარიელია.
ეს ასე არ არის. ამ წარმოდგენაში პლანერის ლოკალური სტატისტიკაა. Autovacuum და analyze standby-ზე არ მუშაობს, სტატისტიკა კი არ რეპლიცირდება, ამიტომ სრულიად ჯანმრთელ რეპლიკაზე იქ კანონიერი ნულია. ნამდვილი შემოწმება — ორივე მხარეს ერთნაირი count(*)-ის გაშვება და primary-ზე pg_current_wal_lsn()-ის შედარება რეპლიკაზე pg_last_wal_replay_lsn()-თან. ორივე ბაზა სტრიქონამდე დაემთხვა.
რატომ ვერავინ შეამჩნია 23 საათი
- ოპერატორის მეტრიკები საერთოდ არ გროვდებოდა: კლასტერს
enablePodMonitor: falseჰქონდა. - მისი ჩართვა საკმარისი არ აღმოჩნდა. kube-prometheus-stack მხოლოდ იმ PodMonitor-ებს იღებს, რომლებსაც მისი საკუთარი
releaseლეიბლი აქვთ, CloudNativePG კი მათზე მხოლოდ თავის ლეიბლებს კიდებს. PodMonitor იქმნებოდა და ჩუმად იგნორირდებოდა, სანამ ლეიბლიpodMonitorMetadata-ით არ დავამატე.
დასკვნები
- რეპლიკა, რომელიც თავის WAL-ს ვერ პოულობს, შეკეთება არ არის. ხელახლა შექმენით primary-დან; ოპერატორი ამას წუთებში აკეთებს.
- standby-ზე ნუ იმსჯელებთ
n_live_tup-ით. შეადარეთ რეალური რაოდენობები და LSN. - შეამოწმეთ, რომ თქვენი მონიტორინგის სტეკი მართლაც ირჩევს თქვენ მიერ შექმნილ PodMonitor-ს. „შექმნილია“ და „გროვდება“ სხვადასხვა რამეა.
- მაღალი ხელმისაწვდომობის ჩუმად დაკარგვა ინციდენტია, მაშინაც კი, თუ მომხმარებლები ვერაფერს ხედავენ.