Klaster pracy awaryjnej PostgreSQL + Patroni. Doświadczenie wdrożeniowe

W artykule opowiem jak podeszliśmy do kwestii odporności na uszkodzenia PostgreSQL, dlaczego stała się dla nas ważna i co się w końcu stało.

Mamy bardzo obciążony serwis: 2,5 miliona użytkowników na całym świecie, ponad 50 100 aktywnych użytkowników każdego dnia. Serwery znajdują się w Amazone w jednym regionie Irlandii: stale działa ponad 50 różnych serwerów, z których prawie XNUMX obsługuje bazy danych.

Cały backend to duża monolityczna stanowa aplikacja Java, która utrzymuje stałe połączenie websocket z klientem. Kiedy kilku użytkowników pracuje jednocześnie na tej samej tablicy, wszyscy widzą zmiany w czasie rzeczywistym, ponieważ każdą zmianę zapisujemy w bazie danych. Mamy około 10 80 żądań na sekundę do naszych baz danych. Przy szczytowym obciążeniu w Redis piszemy 100-XNUMXK żądań na sekundę.
Klaster pracy awaryjnej PostgreSQL + Patroni. Doświadczenie wdrożeniowe

Dlaczego przeszliśmy z Redis na PostgreSQL

Początkowo nasz serwis współpracował z Redis, magazynem klucz-wartość, który przechowuje wszystkie dane w pamięci RAM serwera.

Zalety Redisa:

  1. Wysoka szybkość reakcji, ponieważ wszystko jest przechowywane w pamięci;
  2. Łatwość tworzenia kopii zapasowych i replikacji.

Wady Redis dla nas:

  1. Nie ma prawdziwych transakcji. Próbowaliśmy je zasymulować na poziomie naszej aplikacji. Niestety nie zawsze się to sprawdzało i wymagało pisania bardzo skomplikowanego kodu.
  2. Ilość danych jest ograniczona ilością pamięci. Wraz ze wzrostem ilości danych, pamięć będzie rosła, a na koniec natkniemy się na charakterystykę wybranej instancji, co w AWS wymaga zatrzymania naszego serwisu w celu zmiany typu instancji.
  3. Konieczne jest ciągłe utrzymywanie niskiego poziomu latencji, ponieważ. mamy bardzo dużą liczbę próśb. Optymalny poziom opóźnienia dla nas to 17-20 ms. Na poziomie 30-40 ms otrzymujemy długie odpowiedzi na żądania z naszej aplikacji i degradację usługi. Niestety przydarzyło się to nam we wrześniu 2018 roku, kiedy jedna z instancji z Redis z jakiegoś powodu otrzymała opóźnienie 2 razy większe niż zwykle. Aby rozwiązać ten problem, zatrzymaliśmy usługę w środku dnia z powodu nieplanowanej konserwacji i wymieniliśmy problematyczną instancję Redis.
  4. Łatwo jest uzyskać niespójność danych nawet przy drobnych błędach w kodzie, a następnie spędzić dużo czasu na pisaniu kodu poprawiającego te dane.

Wzięliśmy pod uwagę wady i zdaliśmy sobie sprawę, że musimy przejść na coś wygodniejszego, z normalnymi transakcjami i mniejszą zależnością od opóźnień. Przeprowadziłem badania, przeanalizowałem wiele opcji i wybrałem PostgreSQL.

Przenosimy się na nową bazę danych już od 1,5 roku i przenieśliśmy tylko niewielką część danych, więc teraz pracujemy równolegle z Redis i PostgreSQL. Więcej informacji o etapach przenoszenia i przełączania danych między bazami danych jest napisane w artykuł mojego kolegi.

Kiedy zaczynaliśmy się przenosić, nasza aplikacja działała bezpośrednio z bazą danych i uzyskiwała dostęp do głównych Redis i PostgreSQL. Klaster PostgreSQL składał się z mastera i repliki z replikacją asynchroniczną. Tak wyglądał schemat bazy danych:
Klaster pracy awaryjnej PostgreSQL + Patroni. Doświadczenie wdrożeniowe

Implementacja PgBouncera

Wraz z przeprowadzką rozwijał się również produkt: rosła liczba użytkowników i serwerów współpracujących z PostgreSQL, zaczęło nam brakować połączeń. PostgreSQL tworzy osobny proces dla każdego połączenia i zużywa zasoby. Możesz zwiększyć liczbę połączeń do pewnego momentu, w przeciwnym razie istnieje szansa na uzyskanie nieoptymalnej wydajności bazy danych. Idealną opcją w takiej sytuacji byłoby wybranie menedżera połączeń, który będzie stał przed bazą.

Mieliśmy dwie opcje dla menedżera połączeń: Pgpool i PgBouncer. Ale pierwszy nie obsługuje transakcyjnego trybu pracy z bazą danych, więc wybraliśmy PgBouncer.

Ustaliliśmy następujący schemat pracy: nasza aplikacja uzyskuje dostęp do jednego PgBouncera, za którym znajdują się mastery PostgreSQL, a za każdym masterem jest jedna replika z replikacją asynchroniczną.
Klaster pracy awaryjnej PostgreSQL + Patroni. Doświadczenie wdrożeniowe

Jednocześnie nie mogliśmy przechowywać całej ilości danych w PostgreSQL i ważna była dla nas szybkość pracy z bazą danych, dlatego rozpoczęliśmy sharding PostgreSQL na poziomie aplikacji. Opisany powyżej schemat jest do tego stosunkowo wygodny: przy dodawaniu nowego sharda PostgreSQL wystarczy zaktualizować konfigurację PgBouncer i aplikacja może od razu pracować z nowym shardem.

Przełączanie awaryjne PgBouncera

Ten schemat działał do momentu, gdy zmarła jedyna instancja PgBouncer. Jesteśmy w AWS, gdzie wszystkie instancje działają na sprzęcie, który okresowo umiera. W takich przypadkach instancja po prostu przenosi się na nowy sprzęt i znów działa. Stało się tak z PgBouncer, ale stało się niedostępne. Efektem tego upadku była niedostępność naszego serwisu przez 25 minut. W takich sytuacjach AWS zaleca stosowanie redundancji po stronie użytkownika, która wówczas nie była w naszym kraju wdrażana.

Potem poważnie zastanowiliśmy się nad odpornością na awarie klastrów PgBouncer i PostgreSQL, ponieważ podobna sytuacja może się zdarzyć z każdą instancją na naszym koncie AWS.

Zbudowaliśmy schemat odporności na uszkodzenia PgBouncer w następujący sposób: wszystkie serwery aplikacji uzyskują dostęp do Network Load Balancer, za którym znajdują się dwa PgBouncer. Każdy PgBouncer patrzy na ten sam master PostgreSQL każdego fragmentu. Jeśli awaria instancji AWS wystąpi ponownie, cały ruch zostanie przekierowany przez inny PgBouncer. Przełączanie awaryjne modułu równoważenia obciążenia sieciowego zapewnia AWS.

Ten schemat ułatwia dodawanie nowych serwerów PgBouncer.
Klaster pracy awaryjnej PostgreSQL + Patroni. Doświadczenie wdrożeniowe

Utwórz klaster pracy awaryjnej PostgreSQL

Rozwiązując ten problem, rozważaliśmy różne opcje: samodzielnie napisane przełączanie awaryjne, repmgr, AWS RDS, Patroni.

Skrypty napisane samodzielnie

Mogą monitorować pracę mastera, a jeśli się nie powiedzie, awansować replikę do mastera i aktualizować konfigurację PgBouncer.

Zaletą tego podejścia jest maksymalna prostota, ponieważ sam piszesz skrypty i dokładnie rozumiesz, jak działają.

Wady:

  • Master mógł nie umrzeć, zamiast tego mogła wystąpić awaria sieci. Failover, nieświadomy tego, podniesie replikę do mastera, podczas gdy stary master będzie kontynuował pracę. W efekcie otrzymamy dwa serwery w roli mastera i nie będziemy wiedzieć, który z nich ma najświeższe aktualne dane. Ta sytuacja jest również nazywana rozszczepionym mózgiem;
  • Zostaliśmy bez odpowiedzi. W naszej konfiguracji master i jedna replika po przełączeniu replika przesuwa się do mastera i nie mamy już replik, więc musimy ręcznie dodać nową replikę;
  • Potrzebujemy dodatkowego monitorowania operacji przełączania awaryjnego, podczas gdy mamy 12 fragmentów PostgreSQL, co oznacza, że ​​musimy monitorować 12 klastrów. Wraz ze wzrostem liczby shardów należy również pamiętać o aktualizacji przełączania awaryjnego.

Samodzielnie napisane przełączanie awaryjne wygląda na bardzo skomplikowane i wymaga nietrywialnego wsparcia. W przypadku pojedynczego klastra PostgreSQL byłaby to najłatwiejsza opcja, ale nie skaluje się, więc nie jest dla nas odpowiednia.

Repmgr

Menedżer replikacji dla klastrów PostgreSQL, który może zarządzać działaniem klastra PostgreSQL. Jednocześnie nie ma automatycznego przełączania awaryjnego po wyjęciu z pudełka, więc do pracy będziesz musiał napisać własne „opakowanie” na gotowym rozwiązaniu. Więc wszystko może okazać się jeszcze bardziej skomplikowane niż w przypadku samodzielnie napisanych skryptów, więc nawet nie próbowaliśmy Repmgr.

AWS RDS

Obsługuje wszystko, czego potrzebujemy, wie, jak tworzyć kopie zapasowe i utrzymuje pulę połączeń. Ma automatyczne przełączanie: gdy master umiera, replika staje się nowym masterem, a AWS zmienia rekord dns na nowego mastera, podczas gdy repliki mogą znajdować się w różnych AZ.

Wady obejmują brak precyzyjnych regulacji. Jako przykład dostrajania: nasze instancje mają ograniczenia dla połączeń tcp, czego niestety nie można zrobić w RDS:

net.ipv4.tcp_keepalive_time=10
net.ipv4.tcp_keepalive_intvl=1
net.ipv4.tcp_keepalive_probes=5
net.ipv4.tcp_retries2=3

Dodatkowo AWS RDS jest prawie dwukrotnie droższy od zwykłej instancji, co było głównym powodem rezygnacji z tego rozwiązania.

Patroni

To jest szablon Pythona do zarządzania PostgreSQL z dobrą dokumentacją, automatycznym przełączaniem awaryjnym i kodem źródłowym na github.

Zalety Patroni:

  • Każdy parametr konfiguracyjny jest opisany, jasne jest, jak działa;
  • Automatyczne przełączanie awaryjne działa od razu po wyjęciu z pudełka;
  • Napisany w pythonie, a ponieważ sami dużo piszemy w pythonie, będzie nam łatwiej radzić sobie z problemami, a być może nawet pomóc w rozwoju projektu;
  • W pełni zarządza PostgreSQL, umożliwia zmianę konfiguracji na wszystkich węzłach klastra jednocześnie, a jeśli klaster wymaga ponownego uruchomienia, aby zastosować nową konfigurację, można to zrobić ponownie za pomocą Patroni.

Wady:

  • Z dokumentacji nie wynika jasno, jak poprawnie pracować z PgBouncer. Choć trudno nazwać to minusem, bo zadaniem Patroni jest zarządzanie PostgreSQL, a to jak będą przebiegać połączenia z Patroni to już nasz problem;
  • Przykładów wdrożeń Patroni na dużych wolumenach jest niewiele, natomiast przykładów wdrożeń od podstaw jest wiele.

W rezultacie wybraliśmy Patroni do stworzenia klastra przełączania awaryjnego.

Proces wdrażania Patroni

Przed Patroni mieliśmy 12 shardów PostgreSQL w konfiguracji jednego mastera i jednej repliki z replikacją asynchroniczną. Serwery aplikacji uzyskiwały dostęp do baz danych poprzez Network Load Balancer, za którym znajdowały się dwie instancje z PgBouncer, a za nimi wszystkie serwery PostgreSQL.
Klaster pracy awaryjnej PostgreSQL + Patroni. Doświadczenie wdrożeniowe

Aby wdrożyć Patroni, musieliśmy wybrać konfigurację rozproszonego klastra pamięci masowej. Patroni współpracuje z rozproszonymi systemami przechowywania konfiguracji, takimi jak etcd, Zookeeper, Consul. Po prostu mamy na rynku pełnoprawny klaster Consul, który działa w połączeniu z Vault i już go nie używamy. Świetny powód, aby zacząć używać Consula zgodnie z jego przeznaczeniem.

Jak Patroni współpracuje z konsulem

Mamy klaster Consul, który składa się z trzech węzłów oraz klaster Patroni, który składa się z lidera i repliki (w Patroni master nazywa się liderem klastra, a niewolników replikami). Każda instancja klastra Patroni na bieżąco przesyła informacje o stanie klastra do Konsula. Dlatego od Konsula zawsze możesz dowiedzieć się, jaka jest aktualna konfiguracja klastra Patroni i kto jest w tej chwili liderem.

Klaster pracy awaryjnej PostgreSQL + Patroni. Doświadczenie wdrożeniowe

Aby połączyć Patroni z Consulem, wystarczy przestudiować oficjalną dokumentację, która mówi, że należy podać hosta w formacie http lub https, w zależności od tego, jak współpracujemy z Consulem, oraz schematu połączenia, opcjonalnie:

host: the host:port for the Consul endpoint, in format: http(s)://host:port
scheme: (optional) http or https, defaults to http

Wydaje się to proste, ale tutaj zaczynają się pułapki. Z Consulem pracujemy nad bezpiecznym połączeniem przez https, a nasza konfiguracja połączenia będzie wyglądać następująco:

consul:
  host: https://server.production.consul:8080 
  verify: true
  cacert: {{ consul_cacert }}
  cert: {{ consul_cert }}
  key: {{ consul_key }}

Ale to nie działa. Podczas uruchamiania Patroni nie może połączyć się z Consulem, ponieważ i tak próbuje przejść przez http.

Kod źródłowy Patroni pomógł uporać się z problemem. Dobrze, że jest napisany w pythonie. Okazuje się, że parametr hosta nie jest w żaden sposób analizowany, a protokół musi być określony w schemacie. Tak wygląda u nas działający blok konfiguracyjny do pracy z Consulem:

consul:
  host: server.production.consul:8080
  scheme: https
  verify: true
  cacert: {{ consul_cacert }}
  cert: {{ consul_cert }}
  key: {{ consul_key }}

szablon konsula

Wybraliśmy więc pamięć do konfiguracji. Teraz musimy zrozumieć, w jaki sposób PgBouncer zmieni swoją konfigurację podczas zmiany lidera w klastrze Patroni. W dokumentacji nie ma odpowiedzi na to pytanie, ponieważ. tam w zasadzie praca z PgBouncer nie jest opisana.

Szukając rozwiązania, znaleźliśmy artykuł (niestety nie pamiętam tytułu), w którym napisano, że Сonsul-template bardzo pomógł w parowaniu PgBouncer i Patroni. To skłoniło nas do zbadania, jak działa Consul-template.

Okazało się, że Consul-template stale monitoruje konfigurację klastra PostgreSQL w Consul. Kiedy zmienia się lider, aktualizuje konfigurację PgBouncer i wysyła polecenie przeładowania.

Klaster pracy awaryjnej PostgreSQL + Patroni. Doświadczenie wdrożeniowe

Dużym plusem szablonu jest to, że jest on przechowywany jako kod, więc przy dodawaniu nowego sharda wystarczy wykonać nowy commit i automatycznie zaktualizować szablon, wspierając zasadę Infrastructure as code.

Nowa architektura z Patroni

W rezultacie otrzymaliśmy następujący schemat pracy:
Klaster pracy awaryjnej PostgreSQL + Patroni. Doświadczenie wdrożeniowe

Wszystkie serwery aplikacji uzyskują dostęp do balancera → stoją za nim dwie instancje PgBouncer → w każdej instancji uruchamiany jest Consul-template, który monitoruje status każdego klastra Patroni i monitoruje trafność konfiguracji PgBouncer, która wysyła żądania do obecnego lidera każdego klastra.

Testowanie ręczne

Uruchomiliśmy ten schemat przed uruchomieniem go na małym środowisku testowym i sprawdziliśmy działanie automatycznego przełączania. Otworzyli tablicę, przesunęli naklejkę iw tym momencie „zabili” lidera klastra. W AWS jest to tak proste, jak zamknięcie instancji za pomocą konsoli.

Klaster pracy awaryjnej PostgreSQL + Patroni. Doświadczenie wdrożeniowe

Naklejka powróciła w ciągu 10-20 sekund, a następnie ponownie zaczęła się normalnie poruszać. Oznacza to, że klaster Patroni działał poprawnie: zmienił lidera, wysłał informacje do Сonsul, a Сonsul-template natychmiast odebrał te informacje, zastąpił konfigurację PgBouncer i wysłał polecenie przeładowania.

Jak przetrwać pod dużym obciążeniem i zminimalizować przestoje?

Wszystko działa idealnie! Ale pojawiają się nowe pytania: Jak to będzie działać pod dużym obciążeniem? Jak szybko i bezpiecznie wdrożyć wszystko w produkcji?

Środowisko testowe, na którym przeprowadzamy testy obciążeniowe, pomaga nam odpowiedzieć na pierwsze pytanie. Jest całkowicie identyczny z produkcją pod względem architektury i wygenerował dane testowe, które są w przybliżeniu równe produkcji. Decydujemy się po prostu „zabić” jednego z mistrzów PostgreSQL podczas testu i zobaczyć, co się stanie. Ale wcześniej ważne jest sprawdzenie automatycznego rollowania, ponieważ na tym środowisku mamy kilka shardów PostgreSQL, więc dostaniemy doskonałe testowanie skryptów konfiguracyjnych przed produkcją.

Oba zadania wyglądają ambitnie, ale mamy PostgreSQL 9.6. Czy możemy natychmiast uaktualnić do wersji 11.2?

Decydujemy się zrobić to w 2 krokach: najpierw aktualizacja do wersji 11.2, a następnie uruchomienie Patroni.

Aktualizacja PostgreSQL

Aby szybko zaktualizować wersję PostgreSQL, użyj opcji -k, w którym twarde linki są tworzone na dysku i nie ma potrzeby kopiowania danych. W bazach 300-400 GB aktualizacja trwa 1 sekundę.

Mamy dużo shardów, więc aktualizacja musi odbywać się automatycznie. Aby to zrobić, napisaliśmy poradnik Ansible, który obsługuje za nas cały proces aktualizacji:

/usr/lib/postgresql/11/bin/pg_upgrade 
<b>--link </b>
--old-datadir='' --new-datadir='' 
 --old-bindir=''  --new-bindir='' 
 --old-options=' -c config_file=' 
 --new-options=' -c config_file='

W tym miejscu należy zaznaczyć, że przed rozpoczęciem aktualizacji należy ją wykonać za pomocą parametru --sprawdzaćaby upewnić się, że możesz dokonać aktualizacji. Nasz skrypt dokonuje również podmiany konfiguracji na czas trwania aktualizacji. Nasz skrypt zrealizowany w 30 sekund, co jest znakomitym wynikiem.

Uruchom Patroni

Aby rozwiązać drugi problem, wystarczy spojrzeć na konfigurację Patroni. Oficjalne repozytorium zawiera przykładową konfigurację z initdb, która odpowiada za inicjalizację nowej bazy danych przy pierwszym uruchomieniu Patroni. Ale ponieważ mamy już gotową bazę danych, po prostu usunęliśmy tę sekcję z konfiguracji.

Kiedy zaczęliśmy instalować Patroni na już istniejącym klastrze PostgreSQL i uruchamiać go, napotkaliśmy nowy problem: oba serwery wystartowały jako lider. Patroni nic nie wie o wczesnym stanie klastra i próbuje uruchomić oba serwery jako dwa oddzielne klastry o tej samej nazwie. Aby rozwiązać ten problem, musisz usunąć katalog z danymi na urządzeniu podrzędnym:

rm -rf /var/lib/postgresql/

Należy to zrobić tylko na niewolniku!

Kiedy czysta replika jest podłączona, Patroni tworzy lidera basebackup i przywraca go do repliki, a następnie dogania aktualny stan zgodnie z logami ściany.

Inną napotkaną trudnością jest to, że wszystkie klastry PostgreSQL domyślnie mają nazwę main. Kiedy każdy klaster nie wie nic o drugim, jest to normalne. Ale jeśli chcesz używać Patroni, wszystkie klastry muszą mieć unikalną nazwę. Rozwiązaniem jest zmiana nazwy klastra w konfiguracji PostgreSQL.

próba obciążenia

Uruchomiliśmy test, który symuluje wrażenia użytkownika na tablicach. Kiedy obciążenie osiągnęło naszą średnią dzienną wartość, powtórzyliśmy dokładnie ten sam test, wyłączyliśmy jedną instancję z liderem PostgreSQL. Automatyczne przełączanie awaryjne zadziałało zgodnie z naszymi oczekiwaniami: Patroni zmienił lidera, Consul-template zaktualizował konfigurację PgBouncer i wysłał polecenie przeładowania. Z naszych wykresów w Grafanie wynikało, że występują opóźnienia rzędu 20-30 sekund i niewielka ilość błędów z serwerów związanych z połączeniem z bazą danych. Jest to normalna sytuacja, takie wartości są akceptowalne dla naszego failover i są zdecydowanie lepsze niż przestój usługi.

Wprowadzenie Patroni do produkcji

W rezultacie opracowaliśmy następujący plan:

  • Wdróż Consul-template na serwerach PgBouncer i uruchom;
  • Aktualizacje PostgreSQL do wersji 11.2;
  • Zmień nazwę klastra;
  • Uruchomienie Klastra Patroni.

Jednocześnie nasz schemat pozwala nam zrobić pierwszy punkt prawie w dowolnym momencie, możemy po kolei usuwać każdego PgBouncera z pracy i wdrażać i uruchamiać na nim consul-template. Tak zrobiliśmy.

Do szybkiego wdrożenia wykorzystaliśmy Ansible, ponieważ przetestowaliśmy już wszystkie playbooki na środowisku testowym, a czas wykonania pełnego skryptu wynosił od 1,5 do 2 minut na każdy shard. Moglibyśmy wdrożyć wszystko po kolei do każdego sharda bez zatrzymywania naszej usługi, ale musielibyśmy wyłączyć każdy PostgreSQL na kilka minut. W takim przypadku użytkownicy, których dane znajdują się na tym fragmencie, nie mogliby w tej chwili w pełni działać, a to jest dla nas nie do przyjęcia.

Wyjściem z tej sytuacji była planowa konserwacja, która odbywa się co 3 miesiące. Jest to okno zaplanowanej pracy, kiedy całkowicie wyłączamy nasz serwis i aktualizujemy nasze instancje bazodanowe. Do następnego okienka pozostał tydzień i postanowiliśmy po prostu poczekać i przygotować się dalej. Na czas oczekiwania dodatkowo zabezpieczyliśmy się: dla każdego sharda PostgreSQL postawiliśmy zapasową replikę na wypadek braku zachowania najnowszych danych oraz dodaliśmy nową instancję dla każdego sharda, która powinna stać się nową repliką w klastrze Patroni, aby nie wykonać polecenia usunięcia danych. Wszystko to pomogło zminimalizować ryzyko błędu.
Klaster pracy awaryjnej PostgreSQL + Patroni. Doświadczenie wdrożeniowe

Uruchomiliśmy ponownie nasz serwis, wszystko działało jak należy, użytkownicy pracowali dalej, jednak na wykresach zauważyliśmy nienormalnie duże obciążenie serwerów Consul.
Klaster pracy awaryjnej PostgreSQL + Patroni. Doświadczenie wdrożeniowe

Dlaczego nie widzieliśmy tego w środowisku testowym? Problem ten bardzo dobrze ilustruje konieczność przestrzegania zasady Infrastructure as code i dopracowania całej infrastruktury, od środowisk testowych po produkcyjne. W przeciwnym razie bardzo łatwo jest uzyskać problem, który mamy. Co się stało? Consul najpierw pojawił się na produkcji, a następnie na środowiskach testowych, w efekcie na środowiskach testowych wersja Consula była wyższa niż na produkcji. Tylko w jednym z wydań rozwiązano problem wycieku procesora podczas pracy z consul-template. Dlatego po prostu zaktualizowaliśmy Consul, rozwiązując w ten sposób problem.

Zrestartuj klaster Patroni

Pojawił się jednak nowy problem, którego nawet nie podejrzewaliśmy. Podczas aktualizacji Consul po prostu usuwamy węzeł Consul z klastra za pomocą polecenia consul leave → Patroni łączy się z innym serwerem Consul → wszystko działa. Ale kiedy dotarliśmy do ostatniej instancji klastra Consul i wysłaliśmy do niej polecenie consul leave, wszystkie klastry Patroni po prostu zrestartowały się, aw logach zobaczyliśmy następujący błąd:

ERROR: get_cluster
Traceback (most recent call last):
...
RetryFailedError: 'Exceeded retry deadline'
ERROR: Error communicating with DCS
<b>LOG: database system is shut down</b>

Klaster Patroni nie mógł pobrać informacji o swoim klastrze i został ponownie uruchomiony.

Aby znaleźć rozwiązanie, skontaktowaliśmy się z autorami Patroni za pośrednictwem problemu na github. Zasugerowali ulepszenia naszych plików konfiguracyjnych:

consul:
 consul.checks: []
bootstrap:
 dcs:
   retry_timeout: 8

Udało nam się odtworzyć problem w środowisku testowym i przetestowaliśmy tam te opcje, ale niestety nie zadziałały.

Problem nadal pozostaje nierozwiązany. Planujemy wypróbować następujące rozwiązania:

  • Użyj Consul-agent na każdej instancji klastra Patroni;
  • Napraw problem w kodzie.

Rozumiemy, gdzie wystąpił błąd: problem prawdopodobnie polega na użyciu domyślnego limitu czasu, który nie jest zastępowany przez plik konfiguracyjny. Gdy ostatni serwer Consul zostanie usunięty z klastra, cały klaster Consul zawiesza się na ponad sekundę, z tego powodu Patroni nie może uzyskać statusu klastra i całkowicie restartuje cały klaster.

Na szczęście więcej błędów nie napotkaliśmy.

Wyniki korzystania z Patroni

Po pomyślnym uruchomieniu Patroni dodaliśmy dodatkową replikę w każdym klastrze. Teraz w każdym klastrze istnieje coś na kształt kworum: jeden lider i dwie repliki, stanowiące siatkę bezpieczeństwa w przypadku rozdwojenia mózgów podczas przełączania.
Klaster pracy awaryjnej PostgreSQL + Patroni. Doświadczenie wdrożeniowe

Patroni pracuje nad produkcją od ponad trzech miesięcy. W tym czasie zdążył już nam pomóc. Niedawno w AWS zmarł lider jednego z klastrów, działało automatyczne przełączanie awaryjne, a użytkownicy pracowali dalej. Patroni spełnił swoje główne zadanie.

Małe podsumowanie korzystania z Patroni:

  • Łatwość zmian konfiguracji. Wystarczy zmienić konfigurację na jednej instancji, a zostanie ona podciągnięta do całego klastra. Jeśli do zastosowania nowej konfiguracji wymagane jest ponowne uruchomienie, Patroni poinformuje Cię o tym. Patroni może zrestartować cały klaster za pomocą jednego polecenia, co jest również bardzo wygodne.
  • Automatyczne przełączanie awaryjne działa i już nam pomogło.
  • Aktualizacja PostgreSQL bez przestojów aplikacji. Należy najpierw zaktualizować repliki do nowej wersji, następnie zmienić lidera w klastrze Patroni i zaktualizować starego lidera. W takim przypadku następuje niezbędne testowanie automatycznego przełączania awaryjnego.

Źródło: www.habr.com

Dodaj komentarz