{"id":30356,"date":"2019-10-31T21:35:06","date_gmt":"2019-10-31T18:35:06","guid":{"rendered":"https:\/\/prohoster.info\/blog\/kak-my-ispolzovali-otlozhennuyu-replikatsiyu-dlya-avarijnogo-vosstanovleniya-s-postgresql\/"},"modified":"2019-10-31T21:35:06","modified_gmt":"2019-10-31T18:35:06","slug":"kak-my-ispolzovali-otlozhennuyu-replikatsiyu-dlya-avarijnogo-vosstanovleniya-s-postgresql","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kak-my-ispolzovali-otlozhennuyu-replikatsiyu-dlya-avarijnogo-vosstanovleniya-s-postgresql","title":{"rendered":"Jak wykorzystali\u015bmy op\u00f3\u017anion\u0105 replikacj\u0119 do awaryjnego przywracania z PostgreSQL","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Jak wykorzystali\u015bmy op\u00f3\u017anion\u0105 replikacj\u0119 do awaryjnego przywracania z PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/03\/773f3b6c8d173be91c49066d7067bad3.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nReplikacja to nie kopia zapasowa. Czy\u017c nie? Oto jak wykorzystali\u015bmy op\u00f3\u017anion\u0105 replikacj\u0119 do przywracania danych po przypadkowym usuni\u0119ciu skr\u00f3t\u00f3w.<\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/about.gitlab.com\/handbook\/engineering\/infrastructure\/\">Specjali\u015bci ds. infrastruktury<\/a><\/noindex> na GitLab odpowiadaj\u0105 za dzia\u0142anie <noindex><a rel=\"nofollow\" href=\"https:\/\/gitlab.com\/\">GitLab.com<\/a><\/noindex> \u2014 najwi\u0119kszej instancji GitLab na \u015bwiecie. Tutaj znajduje si\u0119 3 miliony u\u017cytkownik\u00f3w i prawie 7 milion\u00f3w projekt\u00f3w, co czyni go jednym z najwi\u0119kszych otwarto\u017ar\u00f3d\u0142owych serwis\u00f3w SaaS z dedykowan\u0105 architektur\u0105. Bez systemu baz danych PostgreSQL infrastruktura GitLab.com nie przetrwa\u0142aby d\u0142ugo, a to, co robimy dla zapewnienia odporno\u015bci na awarie i ochrony danych, jest niezwykle istotne. Cho\u0107 ma\u0142o prawdopodobne, aby taka katastrofa mia\u0142a miejsce, jeste\u015bmy dobrze przygotowani i dysponujemy r\u00f3\u017cnymi mechanizmami kopii zapasowej i replikacji.<\/p>\n<p><\/p>\n<p>Replikacja to nie to samo, co kopia zapasowa baz danych (<noindex><a rel=\"nofollow\" href=\"https:\/\/about.gitlab.com\/2019\/02\/13\/delayed-replication-for-disaster-recovery-with-postgresql\/#summing-up\">zobacz poni\u017cej<\/a><\/noindex>). Ale teraz przekonamy si\u0119, jak szybko mo\u017cemy przywr\u00f3ci\u0107 przypadkowo usuni\u0119te dane za pomoc\u0105 op\u00f3\u017anionej replikacji: na <noindex><a rel=\"nofollow\" href=\"https:\/\/gitlab.com\/\">GitLab.com<\/a><\/noindex> u\u017cytkownik <noindex><a rel=\"nofollow\" href=\"https:\/\/gitlab.com\/gitlab-com\/gl-infra\/production\/issues\/509\">usuni\u0119to skr\u00f3t<\/a><\/noindex> do projektu <noindex><a rel=\"nofollow\" href=\"https:\/\/gitlab.com\/gitlab-org\/gitlab-ce\/\"><code>gitlab-ce<\/code><\/a><\/noindex> i utracono po\u0142\u0105czenie z \u017c\u0105daniami scalania i zadaniami.<\/p>\n<p><\/p>\n<p>Dzi\u0119ki op\u00f3\u017anionej replikacji przywr\u00f3cili\u015bmy dane w zaledwie 1,5 godziny. Zobacz, jak to wygl\u0105da\u0142o.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3 id=\"vosstanovlenie-na-moment-vremeni-s-postgresql\">Przywracanie do stanu z okre\u015blonego momentu w czasie z PostgreSQL<\/h3>\n<p><\/p>\n<p>PostgreSQL ma wbudowan\u0105 funkcj\u0119, kt\u00f3ra przywraca stan bazy danych do okre\u015blonego momentu. Nazywa si\u0119 ona <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/continuous-archiving.html\">Point-in-Time Recovery<\/a><\/noindex> (PITR) i wykorzystuje te same mechanizmy, kt\u00f3re utrzymuj\u0105 aktualno\u015b\u0107 repliki: zaczynaj\u0105c od wiarygodnego zrzutu ca\u0142ego klastra bazy danych (bazowego kopii zapasowej), stosujemy szereg zmian stanu do okre\u015blonego momentu.<\/p>\n<p><\/p>\n<p>Aby skorzysta\u0107 z tej funkcji dla zimnej kopii zapasowej, regularnie tworzymy bazowe kopie zapasowe bazy danych i przechowujemy je w archiwum (archiwa GitLab s\u0105 przechowywane w <noindex><a rel=\"nofollow\" href=\"https:\/\/cloud.google.com\/storage\/\">chmurze Google<\/a><\/noindex>). Ponadto \u015bledzimy zmiany stanu bazy danych, archiwizuj\u0105c dziennik zapis\u00f3w w prz\u00f3d (<noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/wal-intro.html\">write-ahead log<\/a><\/noindex>, WAL). Dzi\u0119ki temu mo\u017cemy wykona\u0107 PITR dla przywracania po awarii: zaczynamy od zrzutu wykonanego przed b\u0142\u0119dem i stosujemy zmiany z archiwum WAL a\u017c do awarii.<\/p>\n<p><\/p>\n<h3 id=\"chto-takoe-otlozhennaya-replikaciya\">Czym jest op\u00f3\u017aniona replikacja?<\/h3>\n<p><\/p>\n<p>Op\u00f3\u017aniona replikacja to stosowanie zmian z WAL z op\u00f3\u017anieniem. To znaczy, \u017ce transakcja mia\u0142a miejsce w godzinie <code>X<\/code>, ale w replicie pojawi si\u0119 z op\u00f3\u017anieniem <code>d<\/code> o godzin\u0119 <code>X + d<\/code>.<\/p>\n<p><\/p>\n<p>W PostgreSQL istniej\u0105 2 sposoby skonfigurowania fizycznej repliki bazy danych: przywracanie z archiwum i replikacja strumieniowa. <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/archive-recovery-settings.html\">Przywracanie z archiwum<\/a><\/noindex>, w zasadzie dzia\u0142a jak PITR, ale w trybie ci\u0105g\u0142ym: nieustannie wyci\u0105gamy zmiany z archiwum WAL i stosujemy je do repliki. A <noindex><a rel=\"nofollow\" href=\"https:\/\/wiki.postgresql.org\/wiki\/Streaming_Replication\">replikacja strumieniowa<\/a><\/noindex> bezpo\u015brednio wyci\u0105ga strumie\u0144 WAL z nadrz\u0119dnego hosta bazy danych. Preferujemy odzyskiwanie z archiwum \u2014 jest \u0142atwiejsze w zarz\u0105dzaniu i zapewnia normaln\u0105 wydajno\u015b\u0107, kt\u00f3ra nie odbiega od dzia\u0142aj\u0105cego klastra.<\/p>\n<p><\/p>\n<h3 id=\"kak-nastroit-otlozhennoe-vosstanovlenie-iz-arhiva\">Jak skonfigurowa\u0107 op\u00f3\u017anione przywracanie z archiwum<\/h3>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/recovery-config.html\">Opcje odzyskiwania<\/a><\/noindex> s\u0105 opisane w pliku <code>recovery.conf<\/code>. Przyk\u0142ad:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">standby_mode = 'on'\nrestore_command = 'envdir \/etc\/wal-e.d\/env \/opt\/wal-e\/bin\/wal-e wal-fetch -p 4 \"%f\" \"%p\"'\nrecovery_min_apply_delay = '8h'\nrecovery_target_timeline = 'latest'<\/code><\/pre>\n<p><\/p>\n<p>Z tymi parametrami skonfigurowali\u015bmy op\u00f3\u017anion\u0105 replik\u0119 z odzyskiwaniem z archiwum. U\u017cywamy tutaj <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/wal-e\/wal-e\">wal-e<\/a><\/noindex> do wydobywania segment\u00f3w WAL (<code>restore_command<\/code>) z archiwum, a zmiany b\u0119d\u0105 stosowane po o\u015bmiu godzinach (<code>recovery_min_apply_delay<\/code>). Replica b\u0119dzie \u015bledzi\u0107 zmiany w harmonogramie czasowym w archiwum, na przyk\u0142ad w wyniku awarii w klastrze (<code>recovery_target_timeline<\/code>).<\/p>\n<p><\/p>\n<p>Z <code>recovery_min_apply_delay<\/code> mo\u017cna skonfigurowa\u0107 replikacj\u0119 strumieniow\u0105 z op\u00f3\u017anieniem, ale s\u0105 tu pewne pu\u0142apki, kt\u00f3re s\u0105 zwi\u0105zane z slotami replikacji, sprz\u0119\u017ceniem zwrotnym gor\u0105cego zapasowego itd. Archiwum WAL pozwala ich unikn\u0105\u0107.<\/p>\n<p><\/p>\n<p>Parametr <code>recovery_min_apply_delay<\/code> pojawi\u0142o si\u0119 dopiero w PostgreSQL 9.3. W wcze\u015bniejszych wersjach do op\u00f3\u017anionej replikacji trzeba by\u0142o skonfigurowa\u0107 kombinacj\u0119 <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/9.3\/functions-admin.html\">funkcji zarz\u0105dzania przywracaniem<\/a><\/noindex> (<code>pg_xlog_replay_pause(), pg_xlog_replay_resume()<\/code>) lub przechowywa\u0107 segmenty WAL w archiwum przez czas op\u00f3\u017anienia.<\/p>\n<p><\/p>\n<h3 id=\"kak-postgresql-eto-delaet\">Jak PostgreSQL to robi?<\/h3>\n<p><\/p>\n<p>Ciekawe, jak PostgreSQL implementuje op\u00f3\u017anione przywracanie. Sp\u00f3jrzmy na <noindex><a rel=\"nofollow\" href=\"https:\/\/gitlab.com\/postgres\/postgres\/blob\/c24dcd0cfd949bdf245814c4c2b3df828ee7db36\/src\/backend\/access\/transam\/xlog.c#L6124\"><code>recoveryApplyDelay(XlogReaderState)<\/code><\/a><\/noindex>. Jest wywo\u0142ywane z <noindex><a rel=\"nofollow\" href=\"https:\/\/gitlab.com\/postgres\/postgres\/blob\/c24dcd0cfd949bdf245814c4c2b3df828ee7db36\/src\/backend\/access\/transam\/xlog.c#L7196\">g\u0142\u00f3wnej p\u0119tli powt\u00f3rze\u0144<\/a><\/noindex> dla ka\u017cdego rekordu z WAL.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">static bool\nrecoveryApplyDelay(XLogReaderState *record)\n{\n    uint8       xact_info;\n    TimestampTz xtime;\n    long        secs;\n    int         microsecs;\n\n    \n    \/* nic nie do zrobienia, je\u015bli nie skonfigurowano op\u00f3\u017anienia *\/\n    if (recovery_min_apply_delay &lt;= 0)\n        return false;\n\n    \/* nie stosuje si\u0119 op\u00f3\u017anienia na bazie danych, kt\u00f3ra jeszcze nie jest sp\u00f3jna *\/\n    if (!reachedConsistency)\n        return false;\n\n    \/*\n     * Czy to jest rekord COMMIT?\n     *\n     * \u015awiadomie decydujemy si\u0119 nie op\u00f3\u017ania\u0107 abort\u00f3w, poniewa\u017c nie maj\u0105 one wp\u0142ywu na\n     * MVCC. Ju\u017c pozwalamy na powt\u00f3rzenie rekord\u00f3w, kt\u00f3re nie maj\u0105 znacznika czasu,\n     * wi\u0119c ju\u017c istnieje mo\u017cliwo\u015b\u0107 problem\u00f3w spowodowanych wczesnymi konfliktami na\n     * zapasach.\n     * \/\n    if (XLogRecGetRmid(record) != RM_XACT_ID)\n        return false;\n\n    xact_info = XLogRecGetInfo(record) &amp; XLOG_XACT_OPMASK;\n\n    if (xact_info != XLOG_XACT_COMMIT &amp;&amp;\n        xact_info != XLOG_XACT_COMMIT_PREPARED)\n        return false;\n\n    if (!getRecordTimestamp(record, &amp;xtime))\n        return false;\n\n    recoveryDelayUntilTime =\n        TimestampTzPlusMilliseconds(xtime, recovery_min_apply_delay);\n\n    \/*\n     * Wyjd\u017a bez uzbrajania zatrzasku, je\u015bli ju\u017c min\u0105\u0142 czas na zastosowanie tego\n     * rekordu\n     * \/\n    TimestampDifference(GetCurrentTimestamp(), recoveryDelayUntilTime,\n                        &amp;secs, &amp;microsecs);\n    if (secs &lt;= 0 &amp;&amp; microsecs &lt;= 0)\n        return false;\n\n    while (true)\n    {\n        \/\/ Skr\u00f3conae:\n        \/\/ U\u017cyj WaitLatch, a\u017c dotrzemy do recoveryDelayUntilTime\n        \/\/ i wtedy\n        break;\n    }\n    return true;\n}<\/code><\/pre>\n<p><\/p>\n<p>Chodzi o to, \u017ce op\u00f3\u017anienie opiera si\u0119 na czasie fizycznym zapisanym w znaczniku czasu komitowania transakcji (<code>xtime<\/code>). Jak wida\u0107, op\u00f3\u017anienie stosowane jest tylko do komit\u00f3w i nie wp\u0142ywa na inne zapisy \u2014 wszystkie zmiany s\u0105 stosowane bezpo\u015brednio, a komit jest odk\u0142adany, tak \u017ce zobaczymy zmiany dopiero po ustawionym op\u00f3\u017anieniu.<\/p>\n<p><\/p>\n<h3 id=\"kak-ispolzovat-otlozhennuyu-repliku-dlya-vosstanovleniya-dannyh\">Jak u\u017cywa\u0107 op\u00f3\u017anionej repliki do przywracania danych<\/h3>\n<p><\/p>\n<p>Przypu\u015b\u0107my, \u017ce mamy w produkcji klaster bazy danych i replik\u0119 z o\u015bmiogodzinnym op\u00f3\u017anieniem. Zobaczmy, jak przywr\u00f3ci\u0107 dane na przyk\u0142adzie <noindex><a rel=\"nofollow\" href=\"https:\/\/gitlab.com\/gitlab-com\/gl-infra\/production\/issues\/509\">losowego usuni\u0119cia etykiet<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Kiedy dowiedzieli\u015bmy si\u0119 o problemie, <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/9.3\/functions-admin.html\">wstrzymali\u015bmy przywracanie z archiwum<\/a><\/noindex> dla op\u00f3\u017anionej repliki:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">SELECT pg_xlog_replay_pause();<\/code><\/pre>\n<p><\/p>\n<p>Dzi\u0119ki pauzie nie mieli\u015bmy ryzyka, \u017ce replikacja powt\u00f3rzy zapytanie <code>USU\u0143<\/code>. Przydatna rzecz, je\u015bli potrzebujesz czasu, aby wszystko ogarn\u0105\u0107.<\/p>\n<p><\/p>\n<p>Chodzi o to, \u017ce op\u00f3\u017aniona replika powinna dotrze\u0107 do momentu przed zapytaniem <code>USU\u0143<\/code>. Mieli\u015bmy mniej wi\u0119cej \u015bwiadomo\u015b\u0107 fizycznego czasu usuni\u0119cia. Usun\u0119li\u015bmy <code>recovery_min_apply_delay<\/code> i dodali\u015bmy <code>recovery_target_time<\/code> do <code>recovery.conf<\/code>. Tak replika osi\u0105ga odpowiedni moment bez op\u00f3\u017anie\u0144:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">recovery_target_time = '2018-10-12 09:25:00+00'<\/code><\/pre>\n<p><\/p>\n<p>Z znacznikami czasowymi lepiej odj\u0105\u0107 co\u015b ekstra, \u017ceby nie chybi\u0107. Prawda, \u017ce im wi\u0119ksza redukcja, tym wi\u0119cej danych tracimy. Znowu, je\u015bli przegapimy zapytanie, <code>USU\u0143<\/code>, wszystko znowu si\u0119 usunie i b\u0119dziemy musieli zaczyna\u0107 od nowa (albo wzi\u0105\u0107 zimny backup do PITR).<\/p>\n<p><\/p>\n<p>Uruchomili\u015bmy ponownie od\u0142o\u017cony egzemplarz Postgres, a segmenty WAL powtarza\u0142y si\u0119 do wskazanego czasu. Post\u0119p na tym etapie mo\u017cna \u015bledzi\u0107 za pomoc\u0105 zapytania:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">SELECT\n  -- bie\u017c\u0105ca lokalizacja w WAL\n  pg_last_xlog_replay_location(),\n  -- bie\u017c\u0105cy znacznik czasu transakcji (stan repliki)\n  pg_last_xact_replay_timestamp(),\n  -- bie\u017c\u0105cy czas fizyczny\n  now(),\n  -- ilo\u015b\u0107 czasu, kt\u00f3ra wci\u0105\u017c musi by\u0107 zastosowana, a\u017c osi\u0105gni\u0119ty zostanie recovery_target_time\n  '2018-10-12 09:25:00+00'::timestamptz - pg_last_xact_replay_timestamp() as delay;<\/code><\/pre>\n<p><\/p>\n<p>Je\u015bli znacznik czasu przestaje si\u0119 zmienia\u0107, odzyskiwanie zosta\u0142o zako\u0144czone. Mo\u017cna skonfigurowa\u0107 dzia\u0142anie <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/recovery-target-settings.html\"><code>recovery_target_action<\/code><\/a><\/noindex>, aby zamkn\u0105\u0107, przesun\u0105\u0107 lub wstrzyma\u0107 egzemplarz po powt\u00f3rzeniu (domy\u015blnie zostaje wstrzymany).<\/p>\n<p><\/p>\n<p>Baza danych powr\u00f3ci\u0142a do stanu sprzed feralnego zapytania. Teraz mo\u017cna na przyk\u0142ad wyeksportowa\u0107 dane. Wyeksportowali\u015bmy usuni\u0119te dane o skr\u00f3tach oraz wszystkie powi\u0105zania z zadaniami i merge requestami, przenosz\u0105c je do roboczej bazy danych. Je\u015bli straty s\u0105 znaczne, mo\u017cna po prostu przesun\u0105\u0107 replik\u0119 i u\u017cy\u0107 jej jako g\u0142\u00f3wnej. W przeciwnym razie wszystkie zmiany dokonane po momencie, do kt\u00f3rego si\u0119 odzyskali\u015bmy, zostan\u0105 utracone.<\/p>\n<p><\/p>\n<p>Zamiast znacznik\u00f3w czasu lepiej u\u017cywa\u0107 ID transakcji. Warto zapisywa\u0107 te ID, na przyk\u0142ad dla operator\u00f3w DDL (typu <code>DROP TABLE<\/code>), za pomoc\u0105 <code>log_statements = 'ddl'<\/code>. Gdyby\u015bmy mieli ID transakcji, wzi\u0119liby\u015bmy <code>recovery_target_xid<\/code> i przesun\u0119li wszystko do transakcji przed zapytaniem <code>USU\u0143<\/code>.<\/p>\n<p><\/p>\n<p>Powr\u00f3t do dzia\u0142ania jest bardzo prosty: usu\u0144 wszelkie zmiany z <code>recovery.conf<\/code> i uruchom ponownie Postgresa. Wkr\u00f3tce w replikacji znowu pojawi si\u0119 o\u015bmiogodzinna op\u00f3\u017anienie i b\u0119dziemy gotowi na przysz\u0142e trudno\u015bci.<\/p>\n<p><\/p>\n<h3 id=\"preimuschestva-dlya-vosstanovleniya\">Zalety odzyskiwania<\/h3>\n<p><\/p>\n<p>Z od\u0142o\u017con\u0105 replik\u0105 nie trzeba godzinami przywraca\u0107 ca\u0142ego zrzutu z archiwum. Na przyk\u0142ad potrzebujemy pi\u0119ciu godzin, aby wydoby\u0107 ca\u0142y bazowy backup o wielko\u015bci 2 TB. A potem trzeba jeszcze zastosowa\u0107 ca\u0142y dzienny WAL, aby odzyska\u0107 si\u0119 do potrzebnego stanu (w najgorszym przypadku).<\/p>\n<p><\/p>\n<p>Od\u0142o\u017cona replika jest lepsza od zimnego backupu z dw\u00f3ch powod\u00f3w:<\/p>\n<p><\/p>\n<ol>\n<li>Nie trzeba wyjmowa\u0107 ca\u0142ego bazowego backupu z archiwum.<\/li>\n<li>Istnieje sta\u0142e o\u015bmiogodzinne okno segment\u00f3w WAL, kt\u00f3re nale\u017cy powt\u00f3rzy\u0107.<\/li>\n<\/ol>\n<p><\/p>\n<p>\u015aledzimy r\u00f3wnie\u017c mo\u017cliwo\u015b\u0107 wykonania PITR z WAL i szybko zauwa\u017cyliby\u015bmy uszkodzenia lub inne problemy z archiwum WAL, monitoruj\u0105c op\u00f3\u017anienie od\u0142o\u017conej repliki.<\/p>\n<p><\/p>\n<p>W tym przyk\u0142adzie odzyskanie zaj\u0119\u0142o nam 50 minut, co oznacza, \u017ce pr\u0119dko\u015b\u0107 wynosi\u0142a 110 GB danych WAL na godzin\u0119 (archiwum w\u00f3wczas nadal by\u0142o na <noindex><a rel=\"nofollow\" href=\"https:\/\/aws.amazon.com\/s3\/\">AWS S3<\/a><\/noindex>). W sumie rozwi\u0105zali\u015bmy problem i przywr\u00f3cili\u015bmy dane w 1,5 godziny.<\/p>\n<p><\/p>\n<h3 id=\"itogi-gde-prigoditsya-otlozhennaya-replika-a-gde-net\">Podsumowanie: gdzie przyda si\u0119 odroczona replikacja (a gdzie nie)<\/h3>\n<p><\/p>\n<p>U\u017cyj odroczonej replikacji jako \u015brodka pierwszej pomocy, je\u015bli przypadkowo utraci\u0142e\u015b dane i zauwa\u017cy\u0142e\u015b ten problem w granicach ustawionej op\u00f3\u017anienia.<\/p>\n<p><\/p>\n<blockquote><p>Jednak pami\u0119taj: replikacja to nie kopia zapasowa.<\/p><\/blockquote>\n<p>Kopia zapasowa i replikacja maj\u0105 r\u00f3\u017cne cele. Zimna kopia zapasowa przyda si\u0119, je\u015bli przypadkowo zrobi\u0142e\u015b <code>USU\u0143<\/code> lub <code>DROP TABLE<\/code>. Tworzymy kopi\u0119 zapasow\u0105 z zimnego magazynu i przywracamy poprzedni stan tabeli lub ca\u0142ej bazy danych. Ale przy tym zapytanie <code>DROP TABLE<\/code> prawie natychmiastowo powiela si\u0119 w wszystkich replikach na roboczym klastrze, wi\u0119c zwyk\u0142a replikacja tu nie pomo\u017ce. Sama replikacja utrzymuje baz\u0119 danych dost\u0119pn\u0105, gdy poszczeg\u00f3lne serwery s\u0105 obci\u0105\u017cone i rozk\u0142ada obci\u0105\u017cenie.<\/p>\n<p><\/p>\n<p>Nawet z odroczon\u0105 replikacj\u0105 czasami bardzo potrzebujemy zimnej kopii zapasowej w bezpiecznym miejscu, je\u015bli nagle dojdzie do awarii centrum danych, ukrytej usterki lub innych zdarze\u0144, kt\u00f3re natychmiast nie zauwa\u017cysz. Tu od samej replikacji nie ma po\u017cytku.<\/p>\n<p><\/p>\n<p><strong>Uwaga<\/strong>. Na <noindex><a rel=\"nofollow\" href=\"https:\/\/gitlab.com\/\">GitLab.com<\/a><\/noindex> teraz chronimy przed utrat\u0105 danych tylko na poziomie systemu i nie przywracamy danych na poziomie u\u017cytkownika.<\/p>\n<p>\u0179r\u00f3d\u0142o: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/southbridge\/blog\/445446\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0420\u0435\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u044f \u2014 \u043d\u0435 \u0431\u044d\u043a\u0430\u043f. \u0418\u043b\u0438 \u043d\u0435\u0442? \u0412\u043e\u0442 \u043a\u0430\u043a \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u0443\u044e \u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f, \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e \u0443\u0434\u0430\u043b\u0438\u0432 \u044f\u0440\u043b\u044b\u043a\u0438. \u0421\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442\u044b \u043f\u043e \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u043d\u0430 GitLab \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0442 \u0437\u0430 \u0440\u0430\u0431\u043e\u0442\u0443 GitLab.com \u2014 \u0441\u0430\u043c\u043e\u0433\u043e \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 GitLab \u0432 \u043f\u0440\u0438\u0440\u043e\u0434\u0435. \u0417\u0434\u0435\u0441\u044c 3 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u043f\u043e\u0447\u0442\u0438 7 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432, \u0438 \u044d\u0442\u043e \u043e\u0434\u0438\u043d \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u043a\u0440\u0443\u043f\u043d\u044b\u0445 \u043e\u043f\u0435\u043d\u0441\u043e\u0440\u0441-\u0441\u0430\u0439\u0442\u043e\u0432 SaaS \u0441 \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043e\u0439. \u0411\u0435\u0437 \u0441\u0438\u0441\u0442\u0435\u043c\u044b [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":22360,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-30356","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\".\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kak-my-ispolzovali-otlozhennuyu-replikatsiyu-dlya-avarijnogo-vosstanovleniya-s-postgresql\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"pl_PL\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041a\u0430\u043a \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u0443\u044e \u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u0430\u0432\u0430\u0440\u0438\u0439\u043d\u043e\u0433\u043e \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441 PostgreSQL | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\".\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kak-my-ispolzovali-otlozhennuyu-replikatsiyu-dlya-avarijnogo-vosstanovleniya-s-postgresql\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T18:35:06+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:35:06+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Jak wykorzystali\u015bmy odroczon\u0105 replikacj\u0119 do awaryjnego przywracania z PostgreSQL | ProHoster","description":".","canonical_url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kak-my-ispolzovali-otlozhennuyu-replikatsiyu-dlya-avarijnogo-vosstanovleniya-s-postgresql","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pl_PL","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041a\u0430\u043a \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u0443\u044e \u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u0430\u0432\u0430\u0440\u0438\u0439\u043d\u043e\u0433\u043e \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441 PostgreSQL | ProHoster","og:description":".","og:url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kak-my-ispolzovali-otlozhennuyu-replikatsiyu-dlya-avarijnogo-vosstanovleniya-s-postgresql","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T18:35:06+00:00","article:modified_time":"2019-10-31T18:35:06+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"30356","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-21 00:50:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 11:48:29","updated":"2026-01-21 00:50:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/30356","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/comments?post=30356"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/30356\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media\/22360"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media?parent=30356"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/categories?post=30356"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/tags?post=30356"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}