Как ΠΌΡ‹ использовали ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΡƒΡŽ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΡŽ для Π°Π²Π°Ρ€ΠΈΠΉΠ½ΠΎΠ³ΠΎ восстановлСния с PostgreSQL

Как ΠΌΡ‹ использовали ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΡƒΡŽ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΡŽ для Π°Π²Π°Ρ€ΠΈΠΉΠ½ΠΎΠ³ΠΎ восстановлСния с PostgreSQL
РСпликация β€” Π½Π΅ бэкап. Или Π½Π΅Ρ‚? Π’ΠΎΡ‚ ΠΊΠ°ΠΊ ΠΌΡ‹ использовали ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΡƒΡŽ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΡŽ для восстановлСния, случайно ΡƒΠ΄Π°Π»ΠΈΠ² ярлыки.

БпСциалисты ΠΏΠΎ инфраструктурС Π½Π° GitLab ΠΎΡ‚Π²Π΅Ρ‡Π°ΡŽΡ‚ Π·Π° Ρ€Π°Π±ΠΎΡ‚Ρƒ GitLab.com β€” самого большого экзСмпляра GitLab Π² ΠΏΡ€ΠΈΡ€ΠΎΠ΄Π΅. Π—Π΄Π΅ΡΡŒ 3 ΠΌΠΈΠ»Π»ΠΈΠΎΠ½Π° ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ ΠΈ ΠΏΠΎΡ‡Ρ‚ΠΈ 7 ΠΌΠΈΠ»Π»ΠΈΠΎΠ½ΠΎΠ² ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΎΠ², ΠΈ это ΠΎΠ΄ΠΈΠ½ ΠΈΠ· самых ΠΊΡ€ΡƒΠΏΠ½Ρ‹Ρ… опСнсорс-сайтов SaaS с Π²Ρ‹Π΄Π΅Π»Π΅Π½Π½ΠΎΠΉ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€ΠΎΠΉ. Π‘Π΅Π· систСмы Π±Π°Π· Π΄Π°Π½Π½Ρ‹Ρ… PostgreSQL инфраструктура GitLab.com Π΄Π°Π»Π΅ΠΊΠΎ Π½Π΅ ΡƒΠ΅Π΄Π΅Ρ‚, ΠΈ Ρ‡Ρ‚ΠΎ ΠΌΡ‹ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π΅ Π΄Π΅Π»Π°Π΅ΠΌ для отказоустойчивости Π½Π° случаи Π»ΡŽΠ±Ρ‹Ρ… сбоСв, ΠΊΠΎΠ³Π΄Π° ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡ‚Π΅Ρ€ΡΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅. Вряд Π»ΠΈ такая катастрофа случится, Π½ΠΎ ΠΌΡ‹ Ρ…ΠΎΡ€ΠΎΡˆΠΎ ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΈΠ»ΠΈΡΡŒ ΠΈ запаслись Ρ€Π°Π·Π½Ρ‹ΠΌΠΈ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌΠ°ΠΌΠΈ бэкапа ΠΈ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΠΈ.

РСпликация β€” это Π²Π°ΠΌ Π½Π΅ срСдство бэкапа Π±Π°Π· Π΄Π°Π½Π½Ρ‹Ρ… (см. Π½ΠΈΠΆΠ΅). Но сСйчас ΠΌΡ‹ ΡƒΠ²ΠΈΠ΄ΠΈΠΌ, ΠΊΠ°ΠΊ быстро Π²ΠΎΡΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ случайно ΡƒΠ΄Π°Π»Π΅Π½Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΠΎΠΉ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΠΈ: Π½Π° GitLab.com ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ ΡƒΠ΄Π°Π»ΠΈΠ» ярлык для ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° gitlab-ce ΠΈ потСрял связи с ΠΌΠ΅Ρ€ΠΆ-рСквСстами ΠΈ Π·Π°Π΄Π°Ρ‡Π°ΠΌΠΈ.

Π‘ ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΠΎΠΉ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠΎΠΉ ΠΌΡ‹ восстановили Π΄Π°Π½Π½Ρ‹Π΅ всСго Π·Π° 1,5 часа. Π‘ΠΌΠΎΡ‚Ρ€ΠΈΡ‚Π΅, ΠΊΠ°ΠΊ это Π±Ρ‹Π»ΠΎ.

ВосстановлСниС Π½Π° ΠΌΠΎΠΌΠ΅Π½Ρ‚ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ с PostgreSQL

Π£ PostgreSQL Π΅ΡΡ‚ΡŒ встроСнная функция, которая восстанавливаСт состояниС Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… Π½Π° ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ. Она называСтся Point-in-Time Recovery (PITR) ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Ρ‚Π΅ ΠΆΠ΅ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌΡ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°ΡŽΡ‚ Π°ΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠΈ: начиная с достовСрного снимка всСго кластСра Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… (Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ бэкап), ΠΌΡ‹ примСняСм ряд ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ состояния Π΄ΠΎ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠ³ΠΎ ΠΌΠΎΠΌΠ΅Π½Ρ‚Π° Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ.

Π§Ρ‚ΠΎΠ±Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ эту Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ для Ρ…ΠΎΠ»ΠΎΠ΄Π½ΠΎΠ³ΠΎ бэкапа, ΠΌΡ‹ рСгулярно Π΄Π΅Π»Π°Π΅ΠΌ Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ бэкап Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ Ρ…Ρ€Π°Π½ΠΈΠΌ Π΅Π³ΠΎ Π² Π°Ρ€Ρ…ΠΈΠ²Π΅ (Π°Ρ€Ρ…ΠΈΠ²Ρ‹ GitLab ΠΆΠΈΠ²ΡƒΡ‚ Π² ΠΎΠ±Π»Π°Ρ‡Π½ΠΎΠΌ Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅ Google). А Π΅Ρ‰Π΅ отслСТиваСм измСнСния состояния Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ…, архивируя ΠΆΡƒΡ€Π½Π°Π» ΡƒΠΏΡ€Π΅ΠΆΠ΄Π°ΡŽΡ‰Π΅ΠΉ записи (write-ahead log, WAL). И со всСм этим ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ PITR для Π°Π²Π°Ρ€ΠΈΠΉΠ½ΠΎΠ³ΠΎ восстановлСния: Π½Π°Ρ‡ΠΈΠ½Π°Π΅ΠΌ со снимка, сдСланного Π΄ΠΎ ошибки, ΠΈ примСняСм измСнСния ΠΈΠ· Π°Ρ€Ρ…ΠΈΠ²Π° WAL Π²ΠΏΠ»ΠΎΡ‚ΡŒ Π΄ΠΎ сбоя.

Π§Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅ отлоТСнная рСпликация?

ΠžΡ‚Π»ΠΎΠΆΠ΅Π½Π½Π°Ρ рСпликация β€” это ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ ΠΈΠ· WAL с Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠΎΠΉ. Π’ΠΎ Π΅ΡΡ‚ΡŒ транзакция ΠΏΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° Π² час X, Π½ΠΎ Π² Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ΅ ΠΎΠ½Π° появится с Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠΎΠΉ d Π² час X + d.

Π’ PostgreSQL Π΅ΡΡ‚ΡŒ 2 способа Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ Ρ„ΠΈΠ·ΠΈΡ‡Π΅ΡΠΊΡƒΡŽ Ρ€Π΅ΠΏΠ»ΠΈΠΊΡƒ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ…: восстановлСниС ΠΈΠ· Π°Ρ€Ρ…ΠΈΠ²Π° ΠΈ стриминговая рСпликация. ВосстановлСниС ΠΈΠ· Π°Ρ€Ρ…ΠΈΠ²Π°, ΠΏΠΎ сути, Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚, ΠΊΠ°ΠΊ PITR, Π½ΠΎ Π½Π΅ΠΏΡ€Π΅Ρ€Ρ‹Π²Π½ΠΎ: ΠΌΡ‹ постоянно ΠΈΠ·Π²Π»Π΅ΠΊΠ°Π΅ΠΌ измСнСния ΠΈΠ· Π°Ρ€Ρ…ΠΈΠ²Π° WAL ΠΈ примСняСм ΠΈΡ… ΠΊ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ΅. А стриминговая рСпликация Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ ΠΈΠ·Π²Π»Π΅ΠΊΠ°Π΅Ρ‚ ΠΏΠΎΡ‚ΠΎΠΊ WAL ΠΈΠ· Π²Ρ‹ΡˆΠ΅ΡΡ‚ΠΎΡΡ‰Π΅Π³ΠΎ хоста Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ…. ΠœΡ‹ ΠΏΡ€Π΅Π΄ΠΏΠΎΡ‡ΠΈΡ‚Π°Π΅ΠΌ восстановлСниС ΠΈΠ· Π°Ρ€Ρ…ΠΈΠ²Π° β€” ΠΈΠΌ ΠΏΡ€ΠΎΡ‰Π΅ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ ΠΈ Ρƒ Π½Π΅Π³ΠΎ Π½ΠΎΡ€ΠΌΠ°Π»ΡŒΠ½Π°Ρ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ, которая Π½Π΅ отстаСт ΠΎΡ‚ Ρ€Π°Π±ΠΎΡ‡Π΅Π³ΠΎ кластСра.

Как Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΠΎΠ΅ восстановлСниС ΠΈΠ· Π°Ρ€Ρ…ΠΈΠ²Π°

ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ восстановлСния описаны Π² Ρ„Π°ΠΉΠ»Π΅ recovery.conf. ΠŸΡ€ΠΈΠΌΠ΅Ρ€:

standby_mode = 'on'
restore_command = '/usr/bin/envdir /etc/wal-e.d/env /opt/wal-e/bin/wal-e wal-fetch -p 4 "%f" "%p"'
recovery_min_apply_delay = '8h'
recovery_target_timeline = 'latest'

Π‘ этими ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°ΠΌΠΈ ΠΌΡ‹ настроили ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΡƒΡŽ Ρ€Π΅ΠΏΠ»ΠΈΠΊΡƒ с восстановлСниСм ΠΈΠ· Π°Ρ€Ρ…ΠΈΠ²Π°. Π’ΡƒΡ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ wal-e для извлСчСния сСгмСнтов WAL (restore_command) ΠΈΠ· Π°Ρ€Ρ…ΠΈΠ²Π°, Π° измСнСния Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡ‚ΡŒΡΡ Ρ‡Π΅Ρ€Π΅Π· восСмь часов (recovery_min_apply_delay). Π Π΅ΠΏΠ»ΠΈΠΊΠ° Π±ΡƒΠ΄Π΅Ρ‚ ΡΠ»Π΅Π΄ΠΈΡ‚ΡŒ Π·Π° измСнСниями Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ ΡˆΠΊΠ°Π»Ρ‹ Π² Π°Ρ€Ρ…ΠΈΠ²Π΅, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΈΠ·-Π·Π° ΠΎΡ‚Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΎΡ‚ΠΊΠ°Π·Π° Π² кластСрС (recovery_target_timeline).

Π‘ recovery_min_apply_delay ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΡΡ‚Ρ€ΠΈΠΌΠΈΠ½Π³ΠΎΠ²ΡƒΡŽ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΡŽ с Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠΎΠΉ, Π½ΠΎ здСсь Π΅ΡΡ‚ΡŒ ΠΏΠ°Ρ€Π° ΠΏΠΎΠ΄Π²ΠΎΡ…ΠΎΠ², ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ связаны со слотами Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΠΈ, ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠΉ связью горячСго Ρ€Π΅Π·Π΅Ρ€Π²Π° ΠΈ ΠΏΡ€ΠΎΡ‡. Архив WAL позволяСт ΠΈΡ… ΠΈΠ·Π±Π΅ΠΆΠ°Ρ‚ΡŒ.

ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ recovery_min_apply_delay появился Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² PostgreSQL 9.3. Π’ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΡ… вСрсиях для ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΠΎΠΉ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΠΈ Π½ΡƒΠΆΠ½ΠΎ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠ±ΠΈΠ½Π°Ρ†ΠΈΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ управлСния восстановлСниСм (pg_xlog_replay_pause(), pg_xlog_replay_resume()) ΠΈΠ»ΠΈ ΡƒΠ΄Π΅Ρ€ΠΆΠΈΠ²Π°Ρ‚ΡŒ сСгмСнты WAL Π² Π°Ρ€Ρ…ΠΈΠ²Π΅ Π½Π° врСмя Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠΈ.

Как PostgreSQL это Π΄Π΅Π»Π°Π΅Ρ‚?

Π›ΡŽΠ±ΠΎΠΏΡ‹Ρ‚Π½ΠΎ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ, ΠΊΠ°ΠΊ PostgreSQL Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠ΅Ρ‚ ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΠΎΠ΅ восстановлСниС. ΠŸΠΎΡΠΌΠΎΡ‚Ρ€ΠΈΠΌ Π½Π° recoveryApplyDelay(XlogReaderState). Он вызываСтся ΠΈΠ· Π³Π»Π°Π²Π½ΠΎΠ³ΠΎ Ρ†ΠΈΠΊΠ»Π° ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π° для ΠΊΠ°ΠΆΠ΄ΠΎΠΉ записи ΠΈΠ· WAL.

static bool
recoveryApplyDelay(XLogReaderState *record)
{
    uint8       xact_info;
    TimestampTz xtime;
    long        secs;
    int         microsecs;

    /* nothing to do if no delay configured */
    if (recovery_min_apply_delay <= 0)
        return false;

    /* no delay is applied on a database not yet consistent */
    if (!reachedConsistency)
        return false;

    /*
     * Is it a COMMIT record?
     *
     * We deliberately choose not to delay aborts since they have no effect on
     * MVCC. We already allow replay of records that don't have a timestamp,
     * so there is already opportunity for issues caused by early conflicts on
     * standbys.
     */
    if (XLogRecGetRmid(record) != RM_XACT_ID)
        return false;

    xact_info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;

    if (xact_info != XLOG_XACT_COMMIT &&
        xact_info != XLOG_XACT_COMMIT_PREPARED)
        return false;

    if (!getRecordTimestamp(record, &xtime))
        return false;

    recoveryDelayUntilTime =
        TimestampTzPlusMilliseconds(xtime, recovery_min_apply_delay);

    /*
     * Exit without arming the latch if it's already past time to apply this
     * record
     */
    TimestampDifference(GetCurrentTimestamp(), recoveryDelayUntilTime,
                        &secs, &microsecs);
    if (secs <= 0 && microsecs <= 0)
        return false;

    while (true)
    {
        // Shortened:
        // Use WaitLatch until we reached recoveryDelayUntilTime
        // and then
        break;
    }
    return true;
}

Π‘ΡƒΡ‚ΡŒ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠ° основана Π½Π° физичСском Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ, записанном Π² ΠΌΠ΅Ρ‚ΠΊΠ΅ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ ΠΊΠΎΠΌΠΌΠΈΡ‚Π° Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΈ (xtime). Как Π²ΠΈΠ΄Π½ΠΎ, Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠ° примСняСтся Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΊ ΠΊΠΎΠΌΠΌΠΈΡ‚Π°ΠΌ ΠΈ Π½Π΅ Ρ‚Ρ€ΠΎΠ³Π°Π΅Ρ‚ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ записи β€” всС измСнСния ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡŽΡ‚ΡΡ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ, Π° ΠΊΠΎΠΌΠΌΠΈΡ‚ откладываСтся, Ρ‚Π°ΠΊ Ρ‡Ρ‚ΠΎ ΠΌΡ‹ ΡƒΠ²ΠΈΠ΄ΠΈΠΌ измСнСния Ρ‚ΠΎΠ»ΡŒΠΊΠΎ послС настроСнной Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠΈ.

Как ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΡƒΡŽ Ρ€Π΅ΠΏΠ»ΠΈΠΊΡƒ для восстановлСния Π΄Π°Π½Π½Ρ‹Ρ…

Допустим, Ρƒ нас Π² ΠΏΡ€ΠΎΠ΄Π°ΠΊΡˆΠ΅Π½Π΅ Π΅ΡΡ‚ΡŒ кластСр Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ° с Π²ΠΎΡΡŒΠΌΠΈΡ‡Π°ΡΠΎΠ²ΠΎΠΉ Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠΎΠΉ. ΠŸΠΎΡΠΌΠΎΡ‚Ρ€ΠΈΠΌ, ΠΊΠ°ΠΊ Π²ΠΎΡΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ случайного удалСния ярлыков.

Когда ΠΌΡ‹ ΡƒΠ·Π½Π°Π»ΠΈ ΠΎ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ΅, ΠΌΡ‹ приостановили восстановлСниС ΠΈΠ· Π°Ρ€Ρ…ΠΈΠ²Π° для ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΠΎΠΉ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠΈ:

SELECT pg_xlog_replay_pause();

Π‘ ΠΏΠ°ΡƒΠ·ΠΎΠΉ Ρƒ нас Π½Π΅ Π±Ρ‹Π»ΠΎ риска, Ρ‡Ρ‚ΠΎ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ° ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΠΈΡ‚ запрос DELETE. ПолСзная ΡˆΡ‚ΡƒΠΊΠ°, Ссли Π½ΡƒΠΆΠ½ΠΎ врСмя Π²ΠΎ всСм Ρ€Π°Π·ΠΎΠ±Ρ€Π°Ρ‚ΡŒΡΡ.

Π‘ΡƒΡ‚ΡŒ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ отлоТСнная Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ° Π΄ΠΎΠ»ΠΆΠ½Π° Π΄ΠΎΠΉΡ‚ΠΈ Π΄ΠΎ ΠΌΠΎΠΌΠ΅Π½Ρ‚Π° ΠΏΠ΅Ρ€Π΅Π΄ запросом DELETE. ΠœΡ‹ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ Π·Π½Π°Π»ΠΈ физичСскоС врСмя удалСния. ΠœΡ‹ ΡƒΠ΄Π°Π»ΠΈΠ»ΠΈ recovery_min_apply_delay ΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΠ»ΠΈ recovery_target_time Π² recovery.conf. Π’Π°ΠΊ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ° Π΄ΠΎΡ…ΠΎΠ΄ΠΈΡ‚ Π΄ΠΎ Π½ΡƒΠΆΠ½ΠΎΠ³ΠΎ ΠΌΠΎΠΌΠ΅Π½Ρ‚Π° Π±Π΅Π· Π·Π°Π΄Π΅Ρ€ΠΆΠ΅ΠΊ:

recovery_target_time = '2018-10-12 09:25:00+00'

Π‘ ΠΌΠ΅Ρ‚ΠΊΠ°ΠΌΠΈ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ Π»ΡƒΡ‡ΡˆΠ΅ ΡƒΠ±Π°Π²ΠΈΡ‚ΡŒ лишнСго, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ ΠΏΡ€ΠΎΠΌΠ°Ρ…Π½ΡƒΡ‚ΡŒΡΡ. ΠŸΡ€Π°Π²Π΄Π°, Ρ‡Π΅ΠΌ большС ΡƒΠ±Π°Π²ΠΊΠ°, Ρ‚Π΅ΠΌ большС Π΄Π°Π½Π½Ρ‹Ρ… тСряСм. ΠžΠΏΡΡ‚ΡŒ ΠΆΠ΅, Ссли проскочим запрос DELETE, всС ΠΎΠΏΡΡ‚ΡŒ удалится ΠΈ придСтся Π½Π°Ρ‡ΠΈΠ½Π°Ρ‚ΡŒ Π·Π°Π½ΠΎΠ²ΠΎ (ΠΈΠ»ΠΈ Π²ΠΎΠΎΠ±Ρ‰Π΅ Π±Ρ€Π°Ρ‚ΡŒ Ρ…ΠΎΠ»ΠΎΠ΄Π½Ρ‹ΠΉ бэкап для PITR).

ΠœΡ‹ пСрСзапустили ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½Ρ‹ΠΉ экзСмпляр Postgres, ΠΈ сСгмСнты WAL ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΡΠ»ΠΈΡΡŒ Π΄ΠΎ ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠ³ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ. ΠžΡ‚ΡΠ»Π΅Π΄ΠΈΡ‚ΡŒ прогрСсс Π½Π° этом этапС ΠΌΠΎΠΆΠ½ΠΎ запросом:

SELECT
  -- current location in WAL
  pg_last_xlog_replay_location(),
  -- current transaction timestamp (state of the replica)
  pg_last_xact_replay_timestamp(),
  -- current physical time
  now(),
  -- the amount of time still to be applied until recovery_target_time has been reached
  '2018-10-12 09:25:00+00'::timestamptz - pg_last_xact_replay_timestamp() as delay;

Если ΠΌΠ΅Ρ‚ΠΊΠ° Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ большС Π½Π΅ мСняСтся, восстановлСниС Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΎ. МоТно Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ дСйствиС recovery_target_action, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π·Π°ΠΊΡ€Ρ‹Ρ‚ΡŒ, ΠΏΡ€ΠΎΠ΄Π²ΠΈΠ½ΡƒΡ‚ΡŒ ΠΈΠ»ΠΈ ΠΏΡ€ΠΈΠΎΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ экзСмпляр послС ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π° (ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ ΠΎΠ½ приостанавливаСтся).

Π‘Π°Π·Π° Π΄Π°Π½Π½Ρ‹Ρ… ΠΏΡ€ΠΈΡˆΠ»Π° Π² состояниС Π΄ΠΎ Ρ‚ΠΎΠ³ΠΎ злосчастного запроса. Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΠΎΠΆΠ½ΠΎ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΡΠΊΡΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅. ΠœΡ‹ экспортировали ΡƒΠ΄Π°Π»Π΅Π½Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ ΠΎ ярлыкС ΠΈ всС связи с Π·Π°Π΄Π°Ρ‡Π°ΠΌΠΈ ΠΈ ΠΌΠ΅Ρ€ΠΆ-рСквСстами ΠΈ пСрСнСсли ΠΈΡ… Π² Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ…. Если ΠΏΠΎΡ‚Π΅Ρ€ΠΈ ΠΌΠ°ΡΡˆΡ‚Π°Π±Π½Ρ‹Π΅, ΠΌΠΎΠΆΠ½ΠΎ просто ΠΏΡ€ΠΎΠ΄Π²ΠΈΠ½ΡƒΡ‚ΡŒ Ρ€Π΅ΠΏΠ»ΠΈΠΊΡƒ ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π΅Π΅ ΠΊΠ°ΠΊ ΠΎΡΠ½ΠΎΠ²Π½ΡƒΡŽ. Но Ρ‚ΠΎΠ³Π΄Π° ΠΏΠΎΡ‚Π΅Ρ€ΡΡŽΡ‚ΡΡ всС измСнСния послС ΠΌΠΎΠΌΠ΅Π½Ρ‚Π°, Π΄ΠΎ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ ΠΌΡ‹ Π²ΠΎΡΡΡ‚Π°Π½ΠΎΠ²ΠΈΠ»ΠΈΡΡŒ.

ВмСсто ΠΌΠ΅Ρ‚ΠΎΠΊ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ Π»ΡƒΡ‡ΡˆΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ID Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΉ. ПолСзно Π·Π°ΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ эти ID, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, для ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΠ² DDL (Ρ‚ΠΈΠΏΠ° DROP TABLE), с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ log_statements = 'ddl'. Π‘ΡƒΠ΄ΡŒ Ρƒ нас ID Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΈ, ΠΌΡ‹ Π±Ρ‹ взяли recovery_target_xid ΠΈ ΠΏΡ€ΠΎΠ³Π½Π°Π»ΠΈ всС Π²ΠΏΠ»ΠΎΡ‚ΡŒ Π΄ΠΎ Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΈ ΠΏΠ΅Ρ€Π΅Π΄ запросом DELETE.

Π’Π΅Ρ€Π½ΡƒΡ‚ΡŒΡΡ ΠΊ Ρ€Π°Π±ΠΎΡ‚Π΅ ΠΎΡ‡Π΅Π½ΡŒ просто: ΡƒΠ±Π΅Ρ€ΠΈΡ‚Π΅ всС измСнСния ΠΈΠ· recovery.conf ΠΈ пСрСзапуститС Postgres. Π‘ΠΊΠΎΡ€ΠΎ Π² Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ΅ снова появится Π²ΠΎΡΡŒΠΌΠΈΡ‡Π°ΡΠΎΠ²Π°Ρ Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠ°, ΠΈ ΠΌΡ‹ Π³ΠΎΡ‚ΠΎΠ²Ρ‹ ΠΊ Π±ΡƒΠ΄ΡƒΡ‰ΠΈΠΌ нСприятностям.

ΠŸΡ€Π΅ΠΈΠΌΡƒΡ‰Π΅ΡΡ‚Π²Π° для восстановлСния

Π‘ ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΠΎΠΉ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠΎΠΉ вмСсто Ρ…ΠΎΠ»ΠΎΠ΄Π½ΠΎΠ³ΠΎ бэкапа Π½Π΅ приходится часами Π²ΠΎΡΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°Ρ‚ΡŒ вСсь снимок ΠΈΠ· Π°Ρ€Ρ…ΠΈΠ²Π°. Нам, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π½ΡƒΠΆΠ½ΠΎ ΠΏΡΡ‚ΡŒ часов, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π΄ΠΎΡΡ‚Π°Ρ‚ΡŒ вСсь Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ бэкап Π½Π° 2 Π’Π‘. А ΠΏΠΎΡ‚ΠΎΠΌ Π΅Ρ‰Π΅ придСтся ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΡ‚ΡŒ вСсь суточный WAL, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²ΠΎΡΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒΡΡ Π΄ΠΎ Π½ΡƒΠΆΠ½ΠΎΠ³ΠΎ состояния (Π² Ρ…ΡƒΠ΄ΡˆΠ΅ΠΌ случаС).

ΠžΡ‚Π»ΠΎΠΆΠ΅Π½Π½Π°Ρ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ° Π»ΡƒΡ‡ΡˆΠ΅ Ρ…ΠΎΠ»ΠΎΠ΄Π½ΠΎΠ³ΠΎ бэкапа ΠΏΠΎ Π΄Π²ΡƒΠΌ ΠΏΡƒΠ½ΠΊΡ‚Π°ΠΌ:

  1. НС Π½ΡƒΠΆΠ½ΠΎ Π΄ΠΎΡΡ‚Π°Π²Π°Ρ‚ΡŒ вСсь Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ бэкап ΠΈΠ· Π°Ρ€Ρ…ΠΈΠ²Π°.
  2. Π•ΡΡ‚ΡŒ фиксированноС Π²ΠΎΡΡŒΠΌΠΈΡ‡Π°ΡΠΎΠ²ΠΎΠ΅ ΠΎΠΊΠ½ΠΎ сСгмСнтов WAL, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΠΈΡ‚ΡŒ.

А Π΅Ρ‰Π΅ ΠΌΡ‹ постоянно провСряСм, ΠΌΠΎΠΆΠ½ΠΎ Π»ΠΈ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ PITR ΠΈΠ· WAL, ΠΈ ΠΌΡ‹ Π±Ρ‹ быстро Π·Π°ΠΌΠ΅Ρ‚ΠΈΠ»ΠΈ поврСТдСния ΠΈΠ»ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ с Π°Ρ€Ρ…ΠΈΠ²ΠΎΠΌ WAL, слСдя Π·Π° отставаниСм ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΠΎΠΉ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠΈ.

Π’ этом ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ Ρƒ нас ΡƒΡˆΠ»ΠΎ 50 ΠΌΠΈΠ½ΡƒΡ‚ Π½Π° восстановлСниС, Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ Π±Ρ‹Π»Π° 110 Π“Π‘ Π΄Π°Π½Π½Ρ‹Ρ… WAL Π² час (Π°Ρ€Ρ…ΠΈΠ² Ρ‚ΠΎΠ³Π΄Π° всС Π΅Ρ‰Π΅ Π±Ρ‹Π» Π½Π° AWS S3). ВсСго ΠΌΡ‹ Ρ€Π΅ΡˆΠΈΠ»ΠΈ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ ΠΈ восстановили Π΄Π°Π½Π½Ρ‹Π΅ Π·Π° 1,5 часа.

Π˜Ρ‚ΠΎΠ³ΠΈ: Π³Π΄Π΅ пригодится отлоТСнная Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ° (Π° Π³Π΄Π΅ Π½Π΅Ρ‚)

Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΡƒΡŽ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΡŽ ΠΊΠ°ΠΊ срСдство ΠΏΠ΅Ρ€Π²ΠΎΠΉ ΠΏΠΎΠΌΠΎΡ‰ΠΈ, Ссли случайно потСряли Π΄Π°Π½Π½Ρ‹Π΅ ΠΈ Π·Π°ΠΌΠ΅Ρ‚ΠΈΠ»ΠΈ эту Π±Π΅Π΄Ρƒ Π² ΠΏΡ€Π΅Π΄Π΅Π»Π°Ρ… настроСнной Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠΈ.

Но ΡƒΡ‡Ρ‚ΠΈΡ‚Π΅: рСпликация β€” Π½Π΅ бэкап.

Π£ бэкапа ΠΈ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΠΈ Ρ€Π°Π·Π½Ρ‹Π΅ Ρ†Π΅Π»ΠΈ. Π₯ΠΎΠ»ΠΎΠ΄Π½Ρ‹ΠΉ бэкап пригодится, Ссли Π²Ρ‹ случайно сдСлали DELETE ΠΈΠ»ΠΈ DROP TABLE. ΠœΡ‹ Π΄Π΅Π»Π°Π΅ΠΌ бэкап ΠΈΠ· Ρ…ΠΎΠ»ΠΎΠ΄Π½ΠΎΠ³ΠΎ Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π° ΠΈ восстанавливаСм ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅Π΅ состояниС Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ ΠΈΠ»ΠΈ всСй Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ…. Но ΠΏΡ€ΠΈ этом запрос DROP TABLE ΠΏΠΎΡ‡Ρ‚ΠΈ ΠΌΠΎΠΌΠ΅Π½Ρ‚Π°Π»ΡŒΠ½ΠΎ воспроизводится Π²ΠΎ всСх Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ°Ρ… Π½Π° Ρ€Π°Π±ΠΎΡ‡Π΅ΠΌ кластСрС, поэтому обычная рСпликация Ρ‚ΡƒΡ‚ Π½Π΅ спасСт. Π‘Π°ΠΌΠ° ΠΏΠΎ сСбС рСпликация ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ… доступной, ΠΊΠΎΠ³Π΄Π° ΡΠ΄Π°ΡŽΡ‚ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ сСрвСры, ΠΈ распрСдСляСт Π½Π°Π³Ρ€ΡƒΠ·ΠΊΡƒ.

Π”Π°ΠΆΠ΅ с ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΠΎΠΉ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠΎΠΉ Π½Π°ΠΌ ΠΈΠ½ΠΎΠ³Π΄Π° ΠΎΡ‡Π΅Π½ΡŒ Π½ΡƒΠΆΠ΅Π½ Ρ…ΠΎΠ»ΠΎΠ΄Π½Ρ‹Ρ… бэкап Π² бСзопасном мСстС, Ссли Π²Π΄Ρ€ΡƒΠ³ ΠΏΡ€ΠΎΠΈΠ·ΠΎΠΉΠ΄Π΅Ρ‚ сбой Π΄Π°Ρ‚Π°-Ρ†Π΅Π½Ρ‚Ρ€Π°, скрытоС ΠΏΠΎΠ²Ρ€Π΅ΠΆΠ΄Π΅Π½ΠΈΠ΅ ΠΈΠ»ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ события, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ сразу Π½Π΅ Π·Π°ΠΌΠ΅Ρ‚ΠΈΡˆΡŒ. Π’ΡƒΡ‚ ΠΎΡ‚ ΠΎΠ΄Π½ΠΎΠΉ Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΠΈ Ρ‚ΠΎΠ»ΠΊΡƒ Π½Π΅Ρ‚.

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅. На GitLab.com ΠΌΡ‹ сСйчас Π·Π°Ρ‰ΠΈΡ‰Π°Π΅ΠΌ ΠΎΡ‚ ΠΏΠΎΡ‚Π΅Ρ€ΠΈ Π΄Π°Π½Π½Ρ‹Ρ… Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π° ΡƒΡ€ΠΎΠ²Π½Π΅ систСмы ΠΈ Π½Π΅ восстанавливаСм Π΄Π°Π½Π½Ρ‹Π΅ Π½Π° ΡƒΡ€ΠΎΠ²Π½Π΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ