Чӣ тавр мо нусхабардории танбалиро барои барқарорсозии офатҳои табиӣ бо PostgreSQL истифода кардем

Чӣ тавр мо нусхабардории танбалиро барои барқарорсозии офатҳои табиӣ бо PostgreSQL истифода кардем
Нусхабардорӣ нусхабардорӣ нест. Ё не? Ин аст, ки чӣ тавр мо такрори батаъхиргузориро барои барқароршавӣ аз тасодуфан нест кардани миёнабурҳо истифода бурдем.

Мутахассисони инфраструктура GitLab барои кор масъул аст GitLab.com - бузургтарин намунаи GitLab дар табиат. Бо 3 миллион корбар ва тақрибан 7 миллион лоиҳа, он яке аз бузургтарин сайтҳои кушодаи SaaS бо меъмории махсус мебошад. Бе системаи пойгоҳи додаҳои PostgreSQL, инфрасохтори GitLab.com дур нахоҳад рафт ва мо чӣ кор карда истодаем, то таҳаммулпазирии хатогиҳоро дар сурати нокомӣ ҳангоми гум шудани маълумот таъмин кунем. Аз эҳтимол дур нест, ки чунин офат рӯй диҳад, аммо мо омодагии хуб дорем ва бо механизмҳои гуногуни эҳтиётӣ ва такрорӣ захира кардаем.

Репликатсия воситаи нусхабардории пойгоҳи додаҳо нест (нигаред ба поён). Аммо ҳоло мо мебинем, ки чӣ гуна маълумоти тасодуфан ҳазфшударо бо истифода аз такрори танбалӣ зуд барқарор кунем: дар GitLab.com истифодабаранда миёнабурро нест кард барои лоиҳа gitlab-ce ва алоқаҳои гумшуда бо дархостҳо ва вазифаҳои якҷояшавӣ.

Бо як нусхаи таъхиршуда, мо маълумотро дар тӯли 1,5 соат барқарор кардем. Бубинед, ки ин чӣ гуна шуд.

Бо PostgreSQL барқарорсозии вақтро нишон диҳед

PostgreSQL дорои функсияи дарунсохт аст, ки ҳолати пойгоҳи додаҳоро дар як нуқтаи муайян барқарор мекунад. Он ном дорад Барқарорсозии нуқта дар вақт (PITR) ва ҳамон механизмҳоеро истифода мебарад, ки репликаро навсозӣ мекунанд: аз тасвири боэътимоди тамоми кластери пойгоҳи додаҳо (нусхаи эҳтиётӣ), мо як қатор тағиротҳои ҳолатиро то лаҳзаи муайяни вақт татбиқ мекунем.

Барои истифодаи ин хусусият барои нусхабардории сард, мо мунтазам нусхабардории асосии пойгоҳи додаҳо эҷод мекунем ва онро дар бойгонӣ нигоҳ медорем (архивҳои GitLab дар Анбори абрии Google). Мо инчунин тағиротро дар ҳолати пойгоҳи додаҳо тавассути бойгонии сабти пешнавис назорат мекунем (сабти пешакӣ навиштан, 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 (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-ҳои транзаксияро истифода баред. Барои мисол, барои изҳороти DDL сабт кардани ин ID-ҳо муфид аст (масалан DROP TABLE), бо истифода аз log_statements = 'ddl'. Агар мо ID транзаксия медоштем, мо мегирем recovery_target_xid ва ҳама чизро то муомилот пеш аз дархост давида DELETE.

Бозгашт ба кор хеле осон аст: ҳама тағиротҳоро аз recovery.conf ва Postgres-ро аз нав оғоз кунед. Нусхабардорӣ ба зудӣ боз ҳаштсоата таъхир хоҳад дошт ва мо ба мушкилоти оянда омодаем.

Манфиатҳои барқарорсозӣ

Бо нусхаи ба таъхир гузошташуда ба ҷои нусхаи эҳтиётии сард, ба шумо лозим нест, ки барои барқарор кардани тамоми тасвир аз бойгонӣ соатҳо сарф кунед. Масалан, барои гирифтани тамоми нусхаи асосии 2 TB ба мо панҷ соат лозим аст. Ва он гоҳ шумо ба ҳар ҳол бояд тамоми WAL-и ҳаррӯзаро истифода баред, то ба ҳолати дилхоҳ барқарор шавед (дар бадтарин ҳолат).

Нусхаи ба таъхир гузошташуда аз нусхаи хунук бо ду роҳ беҳтар аст:

  1. Барои нест кардани тамоми нусхаи асосӣ аз бойгонӣ лозим нест.
  2. Равзанаи ҳаштсоатаи бахшҳои WAL мавҷуд аст, ки бояд такрор шавад.

Мо инчунин пайваста тафтиш мекунем, ки оё имкони сохтани PITR аз WAL имконпазир аст ва мо бо мониторинги таъхири нусхаи ба таъхир гузошташуда фасод ё дигар мушкилотро дар бойгонии WAL зуд мушоҳида мекунем.

Дар ин мисол, барои барқарор кардани мо 50 дақиқа вақт лозим буд, яъне суръат 110 ГБ WAL дар як соат буд (архив ҳанӯз фаъол буд AWS S3). Дар маҷмӯъ, мо мушкилотро ҳал кардем ва маълумотро дар 1,5 соат барқарор кардем.

Натиҷаҳо: дар куҷо нусхаи ба таъхир гузошташуда муфид аст (ва дар куҷо он нест)

Агар шумо тасодуфан маълумотро гум кунед ва ин мушкилотро дар давоми таъхири танзимшуда пай бурдед, нусхабардории таъхиршударо ҳамчун ёрии аввал истифода баред.

Аммо дар хотир доред: нусхабардорӣ нусхаи эҳтиётӣ нест.

Нусхабардорӣ ва такрорӣ ҳадафҳои гуногун доранд. Нусхаи сард, агар шумо тасодуфан сохта бошед, муфид хоҳад буд DELETE ё DROP TABLE. Мо аз анбори хунук нусхабардорӣ мекунем ва ҳолати қаблии ҷадвал ё тамоми махзани маълумотро барқарор мекунем. Аммо дар айни замой дархост DROP TABLE қариб дар ҳама репликаҳо дар кластери корӣ дубора тавлид мешавад, аз ин рӯ репликатсияи оддӣ дар ин ҷо кӯмак намекунад. Худи нусхабардорӣ пойгоҳи додаҳоро ҳангоми ба иҷора додани серверҳои инфиродӣ дастрас нигоҳ медорад ва сарбориро тақсим мекунад.

Ҳатто бо нусхаи таъхиршуда, мо баъзан воқеан ба як нусхаи эҳтиётии сард дар ҷои бехатар ниёз дорем, агар нокомии маркази додаҳо, осеби пинҳонӣ ё ҳодисаҳои дигаре, ки шумо фавран пай нахоҳед кард. Дар ин ҷо танҳо такрор кардан фоида надорад.

эрод гирифтан. Дар бораи GitLab.com Мо дар айни замон танҳо аз талафи маълумот дар сатҳи система муҳофизат мекунем ва маълумотро дар сатҳи корбар барқарор намекунем.

Манбаъ: will.com

Илова Эзоҳ