PostgreSQL ilə fəlakətin bərpası üçün gecikmiş replikasiyadan necə istifadə etdik

PostgreSQL ilə fəlakətin bərpası üçün gecikmiş replikasiyadan necə istifadə etdik
Replikasiya ehtiyat deyil. Yoxsa yox? Qısayolların təsadüfən silinməsindən sonra bərpa etmək üçün təxirə salınmış replikasiyadan necə istifadə etdiyimiz budur.

İnfrastruktur mütəxəssisləri GitLab işə cavabdehdir GitLab.com - təbiətdəki ən böyük GitLab nümunəsi. 3 milyon istifadəçisi və təxminən 7 milyon layihəsi ilə xüsusi arxitekturaya malik ən böyük açıq mənbəli SaaS saytlarından biridir. PostgreSQL verilənlər bazası sistemi olmadan GitLab.com infrastrukturu uzağa getməyəcək və məlumatların itirilə biləcəyi hər hansı bir nasazlıq halında nasazlığa dözümlülüyü təmin etmək üçün nə edirik. Belə bir fəlakətin baş verməsi ehtimalı azdır, lakin biz yaxşı hazırlaşmışıq və müxtəlif ehtiyat nüsxə və təkrarlama mexanizmləri ilə təchiz olunmuşuq.

Replikasiya verilənlər bazalarının ehtiyat nüsxəsini çıxarmaq vasitəsi deyil (aşağıya baxın). Ancaq indi tənbəl replikasiyadan istifadə edərək təsadüfən silinmiş məlumatları necə tez bərpa edəcəyimizi görəcəyik: açıq GitLab.com istifadəçi qısayolu sildi layihə üçün gitlab-ce və birləşmə sorğuları və tapşırıqları ilə itirilmiş əlaqələr.

Təxirə salınmış bir replika ilə məlumatları cəmi 1,5 saat ərzində bərpa etdik. Görün necə oldu.

PostgreSQL ilə vaxtı bərpa edin

PostgreSQL verilənlər bazasının vəziyyətini müəyyən bir zamana bərpa edən daxili funksiyaya malikdir. Bu adlanır Vaxtında Bərpa (PITR) və replikanı yeni saxlayan eyni mexanizmlərdən istifadə edir: bütün verilənlər bazası klasterinin etibarlı surətindən (baza ehtiyat nüsxəsindən) başlayaraq, biz müəyyən vaxta qədər bir sıra vəziyyət dəyişiklikləri tətbiq edirik.

Soyuq ehtiyat nüsxə üçün bu funksiyadan istifadə etmək üçün biz müntəzəm olaraq baza verilənlər bazasının ehtiyat nüsxəsini çıxarırıq və onu arxivdə saxlayırıq (GitLab arxivləri burada yaşayır) Google bulud yaddaşı). Biz həmçinin qabaqcadan yazma jurnalını arxivləşdirməklə verilənlər bazasının vəziyyətindəki dəyişiklikləri izləyirik (qabaqcadan yazma jurnalı, WAL). Və bütün bunları yerinə yetirməklə, biz fəlakətin bərpası üçün PITR edə bilərik: uğursuzluqdan əvvəl çəkilmiş snapshotdan başlayaraq və WAL arxivindən uğursuzluğa qədər dəyişikliklərin tətbiqi.

Təxirə salınmış replikasiya nədir?

Tənbəl təkrarlama WAL-dan dəyişikliklərin gecikmə ilə tətbiqidir. Yəni əməliyyat bir saat ərzində baş verib X, lakin gecikmə ilə replikada görünəcək d bir saata X + d.

PostgreSQL-in fiziki verilənlər bazası replikasını qurmaq üçün 2 yolu var: ehtiyat nüsxəsinin bərpası və axın replikasiyası. Arxivdən bərpa edilir, mahiyyətcə PITR kimi işləyir, lakin davamlıdır: biz daim WAL arxivindən dəyişiklikləri götürürük və onları replikaya tətbiq edirik. A axın replikasiyası birbaşa WAL axınını yuxarı verilənlər bazası hostundan alır. Biz arxivin bərpasına üstünlük veririk - onu idarə etmək daha asandır və istehsal klasterinə uyğun normal performansa malikdir.

Arxivdən gecikmiş bərpanı necə qurmaq olar

Bərpa Seçimləri faylda təsvir edilmişdir recovery.conf. Nümunə:

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'

Bu parametrlərlə biz ehtiyat bərpası ilə təxirə salınmış replikanı konfiqurasiya etdik. Burada istifadə olunur wal-e WAL seqmentlərini çıxarmaq üçün (restore_command) arxivdən və dəyişikliklər səkkiz saatdan sonra tətbiq olunacaq (recovery_min_apply_delay). Replika arxivdə vaxt qrafiki dəyişikliklərini izləyəcək, məsələn, klaster uğursuzluğu (recovery_target_timeline).

С recovery_min_apply_delay Siz gecikmə ilə axın replikasiyasını qura bilərsiniz, lakin burada replikasiya yuvaları, isti gözləmə rejimində rəy və s. ilə əlaqəli bir neçə tələ var. WAL arxivi onlardan qaçmağa imkan verir.

Parametr recovery_min_apply_delay yalnız PostgreSQL 9.3-də ortaya çıxdı. Əvvəlki versiyalarda təxirə salınmış təkrarlama üçün kombinasiyanı konfiqurasiya etməlisiniz bərpa idarəetmə funksiyaları (pg_xlog_replay_pause(), pg_xlog_replay_resume()) və ya gecikmə müddətində WAL seqmentlərini arxivdə saxlayın.

PostgreSQL bunu necə edir?

PostgreSQL-in tənbəl bərpanı necə həyata keçirdiyini görmək maraqlıdır. Gəlin baxaq recoveryApplyDelay(XlogReaderState). -dən çağırılır əsas təkrar döngəsi WAL-dan hər giriş üçün.

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;
}

Nəticə odur ki, gecikmə əməliyyatın icrası vaxt möhüründə qeydə alınan fiziki vaxta əsaslanır (xtime). Gördüyünüz kimi, gecikmə yalnız öhdəliklərə aiddir və digər qeydlərə təsir göstərmir - bütün dəyişikliklər birbaşa tətbiq edilir və öhdəlik gecikdirilir, buna görə də dəyişiklikləri yalnız konfiqurasiya edilmiş gecikmədən sonra görəcəyik.

Məlumatları bərpa etmək üçün gecikmiş replikadan necə istifadə etmək olar

Tutaq ki, bizim verilənlər bazası klasterimiz və istehsalda səkkiz saat gecikmə ilə replikamız var. Bir nümunədən istifadə edərək məlumatların necə bərpa olunacağına baxaq təsadüfən qısa yolları silmək.

Problemi öyrənəndə biz arxiv bərpası dayandırıldı təxirə salınmış replika üçün:

SELECT pg_xlog_replay_pause();

Fasilə ilə replikanın sorğunu təkrarlayacağı riskimiz yox idi DELETE. Hər şeyi anlamaq üçün vaxta ehtiyacınız varsa, faydalı bir şey.

Məsələ burasındadır ki, təxirə salınmış replika sorğudan əvvəlki ana çatmalıdır DELETE. Biz fiziki olaraq çıxarılma vaxtını təxminən bilirdik. Biz sildik recovery_min_apply_delay və əlavə etdi recovery_target_time в recovery.conf. Replika gecikmədən lazımi məqama belə çatır:

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

Vaxt möhürləri ilə qaçırmamaq üçün artıqlığı azaltmaq daha yaxşıdır. Düzdür, azalma nə qədər çox olarsa, bir o qədər çox məlumat itiririk. Yenə xahişi qaçırsaq DELETE, hər şey yenidən silinəcək və siz yenidən başlamalı olacaqsınız (və ya hətta PITR üçün soyuq ehtiyat nüsxəsini götürməlisiniz).

Biz təxirə salınmış Postgres instansiyasını yenidən işə saldıq və WAL seqmentləri göstərilən vaxta qədər təkrarlandı. Bu mərhələdəki inkişafı izləyə bilərsiniz:

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;

Vaxt damğası artıq dəyişməzsə, bərpa tamamlandı. Fəaliyyət fərdiləşdirilə bilər recovery_target_actiontəkrar cəhddən sonra nümunəni bağlamaq, təşviq etmək və ya dayandırmaq üçün (defolt olaraq dayandırılıb).

Verilənlər bazası bu uğursuz sorğudan əvvəl öz vəziyyətinə qayıtdı. İndi, məsələn, məlumatları ixrac edə bilərsiniz. Biz silinmiş etiket datasını və problemlərə və birləşmə sorğularına bütün keçidləri ixrac etdik və onları istehsal verilənlər bazasına köçürdük. Zərərlər böyük miqyaslıdırsa, sadəcə replikanı təbliğ edə və onu əsas kimi istifadə edə bilərsiniz. Ancaq sonra bərpa etdiyimiz nöqtədən sonra bütün dəyişikliklər itiriləcək.

Vaxt ştampları əvəzinə əməliyyat identifikatorlarından istifadə etmək daha yaxşıdır. Bu identifikatorları, məsələn, DDL ifadələri üçün qeyd etmək faydalıdır (məsələn DROP TABLE), istifadə edərək log_statements = 'ddl'. Əgər əməliyyat identifikatorumuz olsaydı, götürərdik recovery_target_xid və sorğudan əvvəl əməliyyata qədər hər şeyi qaçırdı DELETE.

İşə qayıtmaq çox sadədir: bütün dəyişiklikləri buradan silin recovery.conf və Postgres-i yenidən başladın. Replikanın tezliklə yenidən səkkiz saat gecikməsi olacaq və biz gələcək çətinliklərə hazırıq.

Bərpa Faydaları

Soyuq ehtiyat nüsxəsi əvəzinə təxirə salınmış replika ilə bütün şəkli arxivdən bərpa etmək üçün saatlarla vaxt sərf etməli deyilsiniz. Məsələn, bütün əsas 2 TB ehtiyat nüsxəsini əldə etmək bizə beş saat çəkir. Və sonra istədiyiniz vəziyyətə qayıtmaq üçün bütün gündəlik WAL tətbiq etməlisiniz (ən pis halda).

Təxirə salınmış nüsxə iki cəhətdən soyuq ehtiyat nüsxəsindən daha yaxşıdır:

  1. Bütün əsas ehtiyat nüsxəsini arxivdən çıxarmağa ehtiyac yoxdur.
  2. Təkrarlanmalı olan WAL seqmentlərinin sabit səkkiz saatlıq pəncərəsi var.

Biz həmçinin WAL-dan PITR düzəltməyin mümkün olub-olmadığını yoxlamaq üçün mütəmadi olaraq yoxlayırıq və təxirə salınmış replikanın gecikməsinə nəzarət etməklə WAL arxivində korrupsiya və ya digər problemləri tez bir zamanda görərik.

Bu misalda bərpa etmək bizə 50 dəqiqə çəkdi, yəni sürət saatda 110 GB WAL datası idi (arxiv hələ də açıq idi) AWS S3). Ümumilikdə 1,5 saat ərzində problemi həll etdik və məlumatları bərpa etdik.

Nəticələr: təxirə salınmış nüsxənin faydalı olduğu yerdə (və olmayan yerdə)

Təsadüfən məlumatları itirmisinizsə və bu problemi konfiqurasiya edilmiş gecikmə ərzində görmüsünüzsə, ilk yardım kimi gecikmiş replikasiyadan istifadə edin.

Ancaq unutmayın: replikasiya ehtiyat nüsxə deyil.

Yedəkləmə və təkrarlamanın müxtəlif məqsədləri var. Təsadüfən etsəniz, soyuq bir ehtiyat nüsxə faydalı olacaq DELETE və ya DROP TABLE. Biz soyuq anbardan ehtiyat nüsxəsini çıxarırıq və cədvəlin və ya bütün verilənlər bazasının əvvəlki vəziyyətini bərpa edirik. Amma eyni zamanda istək DROP TABLE demək olar ki, dərhal işləyən klasterdəki bütün replikalarda təkrarlanır, ona görə də adi replikasiya burada kömək etməyəcək. Replikasiyanın özü fərdi serverlər icarəyə verildikdə verilənlər bazasını əlçatan saxlayır və yükü paylayır.

Təxirə salınmış replika ilə belə, məlumat mərkəzinin nasazlığı, gizli zədələnmə və ya dərhal nəzərə çarpmayan digər hadisələr baş verərsə, bəzən təhlükəsiz yerdə soyuq ehtiyat nüsxəsinə ehtiyacımız var. Təkcə təkrarlamanın burada heç bir faydası yoxdur.

Qeyd. Haqqında GitLab.com Hazırda biz yalnız sistem səviyyəsində məlumat itkisindən qoruyuruq və istifadəçi səviyyəsində məlumatları bərpa etmirik.

Mənbə: www.habr.com

Добавить комментарий