← ყველა სტატია

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-ს. „შექმნილია“ და „გროვდება“ სხვადასხვა რამეა.
  • მაღალი ხელმისაწვდომობის ჩუმად დაკარგვა ინციდენტია, მაშინაც კი, თუ მომხმარებლები ვერაფერს ხედავენ.