W ciągu ostatnich kilku miesięcy pracowałem nad aktualizacją online dla bardzo dużych baz danych w ramach projektu AXLE i chciałbym podzielić się swoimi przemyśleniami na ten temat i jakie postępy poczyniliśmy w ostatnim czasie.
Przed dołączeniem do 2nd Quadrant pracowałem w Skypie, gdzie firma nie pozwalała na konserwację naszych baz danych. Oznaczało to, że nie zezwalano na przestoje w przypadku wdrożeń, uaktualnień itp. Tego rodzaju reguła powoduje, że zmieniasz sposób, w jaki robisz rzeczy. Większość zmian jest niewielka, nie wykonujesz żadnych ciężkich blokad, masz repliki pozwalające na szybkie przełączanie awaryjne. Ale chociaż możesz sprawić, że Twoje wydania będą małe i nieblokujące, co się stanie, gdy będziesz musiał dokonać aktualizacji głównej wersji bazy danych PostgreSQL?
Możesz być w innej sytuacji, ponieważ większość firm ma okno aktualizacji, więc możesz pozwolić sobie na przestój podczas aktualizacji. To jednak rodzi dwa problemy. Po pierwsze, żadna firma nie lubi przestojów, nawet jeśli są dozwolone. Co ważniejsze, gdy baza danych rozrośnie się poza gigabajty do zakresu terabajtów lub setek terabajtów, przestój może zająć dni, a nawet tygodnie i nikt nie może sobie pozwolić na zatrzymanie operacji na tak długi czas. W rezultacie wiele firm często pomija ważne aktualizacje, przez co następna jest jeszcze bardziej bolesna. A programistom brakuje nowych funkcji, ulepszeń wydajności. Oni (firmy) czasami nawet ryzykują uruchomieniem wersji PostgreSQL, która nie jest już obsługiwana i ma znane uszkodzenia danych lub problemy z bezpieczeństwem. W kolejnych akapitach opowiem trochę o mojej pracy nad tym, aby aktualizacje były mniej czasochłonne, a co za tym idzie mniej bolesne i, miejmy nadzieję, częstsze.
Zacznę od małej historii. Przed PostgreSQL 9.0 jedynym sposobem na aktualizację głównej wersji było uruchomienie pg_dump i przywrócenie zrzutu do instancji z nowszą wersją PostgreSQL. Ta metoda wymagała odczytania struktury i wszystkich danych z bazy danych i zapisania ich do pliku. Następnie odczytaj plik i wstaw do nowej bazy danych, indeksy muszą zostać odbudowane itp.
Jak możesz sobie wyobrazić, ten proces może zająć trochę czasu. Ulepszenia wydajności zostały wprowadzone w wersji 8.4 dla pg_restore z dodaną opcją -j, gdzie można było określić, ile równoległych zadań ma być uruchomionych. Umożliwia to równoległe przywracanie kilku tabel (indeksów itp.), co przyspiesza proces przywracania zrzutów w formacie niestandardowym. Wersja 9.3 dodała podobną opcję do pg_dump, jeszcze bardziej poprawiając wydajność. Ale biorąc pod uwagę, jak szybko rosną wolumeny danych, sama równoległość nie wystarczy, aby uzyskać poważne korzyści w czasie wymaganym do aktualizacji.
Następnie w PostgreSQL 9.0 pojawiło się narzędzie o nazwie pg_upgrade. Pg_upgrade zrzuca tylko struktury i przywraca je do nowego klastra. Ale kopiuje pliki danych tak, jak są na dysku, co jest znacznie szybsze niż zrzucanie ich do formatu logicznego, a następnie ponowne wstawianie. Jest to wystarczająco dobre dla małych baz danych, ponieważ oznacza przestój w zakresie minut lub godzin, czas akceptowalny dla wielu scenariuszy. Istnieje również tryb łącza, który po prostu tworzy twarde łącza (punkty połączeń w systemie Windows), co jeszcze bardziej przyspiesza ten proces. Ale z mojego osobistego punktu widzenia uruchamianie takiej konfiguracji na głównym serwerze produkcyjnym jest zbyt niebezpieczne. Pokrótce wyjaśnię dlaczego. Jeśli coś pójdzie nie tak, po uruchomieniu nowego serwera, który został zaktualizowany w trybie łącza, nagle tracisz produkcyjną bazę danych i musisz przejść w tryb awaryjny lub, co gorsza, musisz przywrócić dane z kopii zapasowej. Oznacza to, że nie tylko nie udało Ci się dokonać aktualizacji, ale spowodowałeś dodatkowy przestój! Powodzenia w uzyskaniu zgody następnym razem.
Obecnie wiele osób, które nie mogą sobie pozwolić na długie przestoje związane z aktualizacją, korzysta z rozwiązań replikacji opartych na wyzwalaczach, takich jak Slony lub Londiste, aby przeprowadzić aktualizację. Jest to dobre rozwiązanie, ponieważ możesz replikować swoje dane, gdy oryginalny serwer jest uruchomiony, a następnie przełączać się z minimalnym przestojem. W praktyce istnieje jednak kilka problemów. Jednym z nich jest to, że rozwiązania oparte na wyzwalaczach są często niezgrabne w konfiguracji, zwłaszcza jeśli robisz to tylko raz na kilka lat i tylko w celu aktualizacji. Łatwo też pominąć tabelę lub dodać tabele w złej kolejności, a tym samym nie otrzymać pełnej kopii. Byłem tego świadkiem w praktyce, a osoby dokonujące aktualizacji codziennie pracowały z replikacją opartą na wyzwalaczu . Inną kwestią jest to, że rozwiązania oparte na wyzwalaczach znacznie obciążają źródłową bazę danych, czasami uniemożliwiając aktualizację z powodu przeciążenia serwera bazy danych po uruchomieniu replikacji. I wreszcie, ale często nie mniej ważne, może minąć bardzo dużo czasu, zanim replikacja oparta na wyzwalaczu faktycznie przeniesie dane na nowy serwer. Ostatnim razem, gdy brałem udział w projekcie aktualizacji, rozwiązanie oparte na wyzwalaczu zajęło około miesiąca, aby skopiować bazę danych i nadrobić zaległości. Tak, jeden miesiąc.
Wraz z PostgreSQL 9.4 pojawia się funkcja logicznego dekodowania, która oferuje nowy początek w projektowaniu nowego i lepszego rozwiązania problemu aktualizacji online. W ramach projektu AXLE stworzyliśmy narzędzie, które łączy logiczne dekodowanie z opisanymi powyżej technikami. Rozwiązanie rozwiązuje większość problemów poprzednich podejść. Rozszerzenie PostgreSQL Uni-Directional Replication (w skrócie UDR) wykonuje replikację logiczną przy użyciu logicznego dekodowania dziennika zapisu z wyprzedzeniem (WAL). Dzięki temu wpływ na serwer główny jest prawie równy z fizyczną replikacją strumieniową, więc dodatkowe obciążenie spowodowane trwającą aktualizacją jest minimalne na uruchomionym systemie. Zapewnia również narzędzia do inicjowania nowych węzłów, zarówno przy użyciu fizycznej, jak i logicznej kopii zapasowej. Możesz nawet zmienić istniejący fizyczny tryb gotowości na tryb gotowości UDR. A ponieważ jest to system replikacji logicznej, możliwe jest zaprojektowanie go w sposób, który obsługuje replikację między wersjami.
Oznacza to, że możemy teraz używać UDR w połączeniu z pg_upgrade do aktualizacji online głównej wersji PostgreSQL z minimalnym przestojem, w krótkim czasie bezwzględnym i przy minimalnym wpływie na działający system.
Przykład, jak to może wyglądać w praktyce:
- Wykonaj pg_basebackup istniejącej instancji.
- Skonfiguruj replikację UDR między oryginalną instancją a tą utworzoną przez basebackup.
- Pg_upgrade nową instancję.
- Pozwól UDR odtworzyć zmiany, które zaszły w międzyczasie.
- Przełącz ruch do nowej instancji.
Więcej szczegółowych instrukcji znajdziesz w przewodniku UDR Online Upgrade na wiki PostgreSQL. Źródła UDR są dostępne w repozytorium 2ndquadrant_bdr na serwerze git PostgreSQL (bdr-plugin/next branch).
Wreszcie, ponieważ UDR to nie tylko narzędzie do aktualizacji online, ale także rozwiązanie do replikacji, może być używane do normalnych potrzeb replikacji zamiast fizycznej replikacji strumieniowej. Ponadto zapewnia kilka korzyści, takich jak możliwość tworzenia tabel tymczasowych, replikacja z wielu baz danych OLTP do jednej bazy danych hurtowni danych Big Data lub replikacja tylko części bazy danych.
Mam nadzieję, że ten wysiłek sprawi, że względy związane z przestojami nie będą już problemem, jeśli chodzi o aktualizację z PostgreSQL 9.4 i nowszych do nowej głównej wersji.
Badania prowadzące do tych wyników otrzymały finansowanie z Siódmego Programu Ramowego Unii Europejskiej (FP7/2007-2013) w ramach umowy o grant nr 318633.