პროდაქშენის Postgres-ის გადატანა RDS Multi-AZ instance-დან Multi-AZ DB cluster-ზე
დაგეგმილი cutover თითქმის მონაცემების დაკარგვის გარეშე — და სამი ხაფანგი: „ტექსამუშაოები“, რომლებმაც ჩაწერა ვერ შეაჩერეს, პაროლები, რომელთა კოპირებასაც RDS არ იძლევა, და დამპი 25 წუთში VPN-ით 31 წამის წინააღმდეგ VPC-ში.
Gambchamp-ში ცოცხალ პროდაქშენის PostgreSQL-ს ვაგადატანდით RDS Multi-AZ instance-დან Multi-AZ DB cluster-ზე: writer პლუს ორი წასაკითხი standby და ცალკე reader-endpoint. აპლიკაცია უნდა გადაგვერთო, როლები, მონაცემები და გრანტები ერთი ერთზე გადაგვეტანა, მონაცემების დანაკარგი კი თითქმის ნულამდე დაგვეყვანა.
ეს დაგეგმილი მიგრაცია იყო და არა ინციდენტი. სამმა რამემ მაინც გვიკბინა.
პირველი ხაფანგი: „ტექსამუშაოებმა“ ჩაწერა ვერ შეაჩერეს
აპლიკაცია ტექსამუშაოების რეჟიმში გადავიყვანეთ და ცხრილების მიხედვით სტრიქონების ზუსტი რაოდენობა ორ მომენტში შევადარეთ. ხუთი ცხრილი ისევ იცვლებოდა: გადახდის პროვაიდერების callback-ები, შეტყობინებები და ვიზიტები ისევ ემატებოდა. ცოცხალი წყაროს ერთი დამპი ყოველთვის ჩამორჩება.
ნამდვილი გაყინვა — ყველა ჩამწერის ნულამდე დასკეილება და ამის დამტკიცება: რაოდენობები სტაბილურია, ჩამწერი კავშირები არ არის, idle-in-transaction სესიები არ არის. ამას ზემოდან, წყაროზე:
ALTER DATABASE app SET default_transaction_read_only = on;
პლუს აპლიკაციის დარჩენილი კავშირების დასრულება. ეს ბლოკავს ნებისმიერ დაგვიანებულ ჩაწერას და გადართვის შემდეგ split-brain-საც უშლის ხელს.
მეორე ხაფანგი: RDS პაროლებს არ გაძლევთ
pg_dumpall --globals-only როლების გადატანის ჩვეულებრივი გზაა. RDS-ზე master-საც კი არ შეუძლია pg_authid-ის წაკითხვა, ამიტომ იქიდან ვერც ჰეშებს მიიღებთ, ვერც სხვა რამეს. pg_dumpall -g --no-role-passwords მაინც იძლევა ზუსტ ატრიბუტებს, წევრობებსა და როლების პარამეტრებს — ეს ღირს.
პაროლები სხვაგან უნდა აგვეღო. აპლიკაციის როლმა პროდაქშენის პაროლი შეინარჩუნა — ის აპლიკაციის Kubernetes-საიდუმლოდან ავიღეთ და წყაროზე რეალური ლოგინით შევამოწმეთ. დამხმარე როლებმა ახალი პაროლები მიიღეს. როლი, რომელსაც უკვე ვადა ჰქონდა გასული, ვადაგასულად შეიქმნა.
მესამე ხაფანგი: ყველაფერი ქსელმა გადაწყვიტა
დამპი VPN-ით ძლივს მიდიოდა: 110 MB დაახლოებით 25 წუთში. იგივე pg_dump იმავე VPC-ში მყოფი EC2-ჰოსტიდან 31 წამში დასრულდა. პაროლები stdin-ით გადაეცემოდა და არასოდეს — ბრძანების არგუმენტებით.
აღდგენის დეტალები, რომლებიც ადვილად გამოგრჩებათ
- RDS-ზე master ბაზის მფლობელი არ არის, ამიტომ
DROP DATABASEარ გადის. სუფთა სამიზნეpublicსქემის წაშლითა და ხელახლა შექმნით გავაკეთეთ მფლობელი როლის სახელით.CREATE EXTENSION-ს ისევ master სჭირდება. - აღდგენისას ორი შეცდომა მოსალოდნელია.
ALTER DEFAULT PRIVILEGES FOR ROLE <app>master-ით ეცემა და იმ როლის სახელით უნდა გამეორდეს.publication already existsჩნდება, რადგან პუბლიკაციები ბაზის დონის ობიექტებია დაDROP SCHEMA-ს გადაურჩებიან.
შემოწმება გახსნამდე
- ცხრილების მიხედვით რაოდენობების სრული diff ნულის ტოლია;
- თითოეული sequence შედარებულია თავისი სვეტის მაქსიმუმთან — ჩამორჩენილი sequence პირველივე ჩაწერისას
duplicate key-ს ნიშნავს; - რეალური ლოგინი ყოველი როლით და საცდელი ჩაწერა აპლიკაციის როლით.
მხოლოდ ამის შემდეგ გადავიყვანეთ აპლიკაციის ჰოსტი კლასტერის writer-endpoint-ზე, კითხვა კი reader-endpoint-ზე. ძველი instance იზოლირებული დარჩა: read-only და აპლიკაციის არც ერთი კავშირის გარეშე.
დაბრუნება მარტივია, სანამ პირველი ჩაწერა კლასტერში არ მოხვდა: ძველ instance-ზე default_transaction_read_only გადატვირთეთ და ჰოსტი დააბრუნეთ. პირველი ჩაწერის შემდეგ — დაუბრუნებლობის წერტილია.
დასკვნები
- გაყინვა რაოდენობების diff-ით დაამტკიცეთ. Callback-ები და webhook-ები „ტექსამუშაოების“ შემდეგაც წერენ.
- RDS-ზე დაგეგმეთ პაროლების ხელახლა გაცემა ან აიღეთ ისინი აპლიკაციის საიდუმლოებიდან; ბაზიდან მათ ვერ დააკოპირებთ.
- დამპი და აღდგენა VPC-ის შიგნიდან გაუშვით. აქ ეს დაახლოებით 50-ჯერ უფრო სწრაფი იყო.
- ჩაწერის გახსნამდე sequence-ები სვეტებთან შეადარეთ.
- მონიტორინგი ბაზას თავისით არ მიჰყვება — აპლიკაციის გადართვა cutover-ის მხოლოდ ნახევარია.