Πώς χρησιμοποιήσαμε το Lazy Replication για αποκατάσταση από καταστροφή με το PostgreSQL

Πώς χρησιμοποιήσαμε το Lazy Replication για αποκατάσταση από καταστροφή με το PostgreSQL
Η αναπαραγωγή δεν είναι αντίγραφο ασφαλείας. Ή όχι? Δείτε πώς χρησιμοποιήσαμε το lazy replication για ανάκτηση διαγράφοντας κατά λάθος συντομεύσεις.

ειδικών υποδομών Το GitLab είναι υπεύθυνο για την εργασία GitLab.com - το μεγαλύτερο παράδειγμα του GitLab στη φύση. Με 3 εκατομμύρια χρήστες και σχεδόν 7 εκατομμύρια έργα, είναι ένας από τους μεγαλύτερους ιστότοπους SaaS ανοιχτού κώδικα με αποκλειστική αρχιτεκτονική. Χωρίς το σύστημα βάσης δεδομένων PostgreSQL, η υποδομή GitLab.com δεν θα πάει μακριά και αυτό που απλώς δεν κάνουμε για την ανοχή σφαλμάτων σε περίπτωση οποιωνδήποτε αστοχιών όταν μπορεί να χάσετε δεδομένα. Είναι απίθανο να συμβεί μια τέτοια καταστροφή, αλλά προετοιμαστήκαμε καλά και εφοδιαστήκαμε με διάφορους μηχανισμούς δημιουργίας αντιγράφων ασφαλείας και αναπαραγωγής.

Η αναπαραγωγή δεν είναι το εργαλείο δημιουργίας αντιγράφων ασφαλείας της βάσης δεδομένων σας (Δες παρακάτω). Αλλά τώρα θα δούμε πώς να ανακτήσετε γρήγορα δεδομένα που έχουν διαγραφεί κατά λάθος χρησιμοποιώντας lazy replication: on GitLab.com χρήστη καταργήθηκε η συντόμευση για το έργο gitlab-ce και χαμένες συνδέσεις με αιτήματα συγχώνευσης και εργασίες.

Με καθυστερημένη αντιγραφή, ανακτήσαμε δεδομένα σε μόλις 1,5 ώρα. Δείτε πώς ήταν.

Ανάκτηση σε χρόνο με την PostgreSQL

Η PostgreSQL έχει μια ενσωματωμένη λειτουργία που επαναφέρει την κατάσταση μιας βάσης δεδομένων σε ένα συγκεκριμένο χρονικό σημείο. Ονομάζεται Ανάκτηση σημείου χρόνου (PITR) και χρησιμοποιεί τους ίδιους μηχανισμούς που διατηρούν ένα αντίγραφο ενημερωμένο: ξεκινώντας με ένα αξιόπιστο στιγμιότυπο ολόκληρου του συμπλέγματος βάσης δεδομένων (backup βάσης), εφαρμόζουμε μια σειρά αλλαγών κατάστασης μέχρι μια συγκεκριμένη χρονική στιγμή.

Για να χρησιμοποιήσουμε αυτήν τη δυνατότητα για κρύο αντίγραφο ασφαλείας, κάνουμε τακτικά αντίγραφα ασφαλείας βάσης δεδομένων βάσης και το αποθηκεύουμε σε ένα αρχείο (τα αρχεία του GitLab βρίσκονται στο Google cloud αποθήκευσης). Παρακολουθούμε επίσης τις αλλαγές της κατάστασης της βάσης δεδομένων αρχειοθετώντας ένα αρχείο καταγραφής εγγραφής (γράψτε ημερολόγιο μπροστά, WAL). Και με όλα αυτά, μπορούμε να κάνουμε PITR για αποκατάσταση από καταστροφή: ξεκινάμε με ένα στιγμιότυπο που τραβήχτηκε πριν από το σφάλμα και εφαρμόζουμε τις αλλαγές από το αρχείο WAL μέχρι τη συντριβή.

Τι είναι η καθυστερημένη αναπαραγωγή;

Καθυστερημένη αναπαραγωγή είναι η εφαρμογή αλλαγών από το WAL με καθυστέρηση. Δηλαδή, η συναλλαγή έγινε την ώρα X, αλλά θα εμφανιστεί στο αντίγραφο με καθυστέρηση d σε μια ώρα X + d.

Υπάρχουν 2 τρόποι για να ρυθμίσετε ένα αντίγραφο φυσικής βάσης δεδομένων στο PostgreSQL: επαναφορά αρχείου και αναπαραγωγή ροής. Επαναφορά από αρχείο, ουσιαστικά λειτουργεί όπως το 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). Το Replica θα παρακολουθεί για αλλαγές στο χρονοδιάγραμμα στο αρχείο, όπως λόγω αποτυχίας συμπλέγματος (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 υλοποιεί το lazy restore. Ας δούμε 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). Όπως μπορείτε να δείτε, η καθυστέρηση ισχύει μόνο για δεσμεύσεις και δεν επηρεάζει άλλες εγγραφές - όλες οι αλλαγές εφαρμόζονται απευθείας και η δέσμευση καθυστερεί, επομένως θα δούμε τις αλλαγές μόνο μετά τη ρυθμισμένη καθυστέρηση.

Πώς να χρησιμοποιήσετε το lazy replica για την ανάκτηση δεδομένων

Ας υποθέσουμε ότι έχουμε ένα σύμπλεγμα βάσεων δεδομένων στην παραγωγή και ένα αντίγραφο με καθυστέρηση οκτώ ωρών. Ας δούμε πώς να ανακτήσετε δεδομένα χρησιμοποιώντας ένα παράδειγμα τυχαία διαγραφή συντομεύσεων.

Όταν συνειδητοποιήσαμε το πρόβλημα, εμείς σε παύση ανάκτηση αντιγράφων ασφαλείας για καθυστερημένη αντιγραφή:

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για να κλείσετε, να προωθήσετε ή να θέσετε σε παύση την παρουσία μετά από μια επανάληψη (παύση από προεπιλογή).

Η βάση δεδομένων περιήλθε στην πολιτεία πριν από αυτό το ατυχές αίτημα. Τώρα μπορείτε, για παράδειγμα, να εξάγετε δεδομένα. Εξάγαμε τα δεδομένα απομακρυσμένων ετικετών και όλους τους συνδέσμους σε ζητήματα και αιτήματα συγχώνευσης και τα μεταφέραμε στη βάση δεδομένων παραγωγής. Εάν οι απώλειες είναι μεγάλες, μπορείτε απλά να προωθήσετε το αντίγραφο και να το χρησιμοποιήσετε ως το κύριο. Αλλά τότε όλες οι αλλαγές θα χαθούν μετά τη στιγμή στην οποία ανακάμψαμε.

Είναι προτιμότερο να χρησιμοποιείτε αναγνωριστικά συναλλαγών αντί για χρονικές σημάνσεις. Είναι χρήσιμο να καταγράφονται αυτά τα αναγνωριστικά, για παράδειγμα, για δηλώσεις DDL (όπως π.χ DROP TABLE), με τη χρήση log_statements = 'ddl'. Αν είχαμε αναγνωριστικό συναλλαγής θα παίρναμε recovery_target_xid και έτρεξε τα πάντα στη συναλλαγή πριν από το αίτημα DELETE.

Η επιστροφή στην εργασία είναι πολύ απλή: καταργήστε όλες τις αλλαγές από recovery.conf και επανεκκινήστε το postgres. Σύντομα το σύνθημα θα έχει και πάλι οκτάωρη καθυστέρηση και είμαστε έτοιμοι για μελλοντικά προβλήματα.

Οφέλη αποκατάστασης

Με ένα καθυστερημένο αντίγραφο, αντί για ένα κρύο αντίγραφο ασφαλείας, δεν χρειάζεται να ξοδεύετε ώρες για να επαναφέρετε ολόκληρο το στιγμιότυπο από το αρχείο. Για παράδειγμα, χρειαζόμαστε πέντε ώρες για να λάβουμε ολόκληρο το αντίγραφο ασφαλείας των 2 TB βάσης. Και τότε πρέπει ακόμα να εφαρμόσετε ολόκληρο το ημερήσιο WAL για να ανακτήσετε στην επιθυμητή κατάσταση (στη χειρότερη περίπτωση).

Ένα καθυστερημένο αντίγραφο είναι καλύτερο από ένα ψυχρό αντίγραφο με δύο τρόπους:

  1. Δεν χρειάζεται να λάβετε ολόκληρο το αντίγραφο ασφαλείας της βάσης από το αρχείο.
  2. Υπάρχει ένα σταθερό παράθυρο οκτώ ωρών τμημάτων WAL που πρέπει να επαναληφθούν.

Επίσης, ελέγχουμε συνεχώς εάν το WAL μπορεί να γίνει PITR και θα παρατηρούσαμε γρήγορα καταστροφή ή άλλα προβλήματα με το αρχείο του WAL παρακολουθώντας το ανεκτέλεστο του καθυστερημένου αντιγράφου.

Σε αυτό το παράδειγμα, μας πήρε 50 λεπτά για να επαναφέρουμε, δηλαδή, η ταχύτητα ήταν 110 GB δεδομένων WAL ανά ώρα (το αρχείο ήταν ακόμα ενεργό AWS S3). Συνολικά, λύσαμε το πρόβλημα και επαναφέραμε τα δεδομένα σε 1,5 ώρα.

Περίληψη: όπου είναι χρήσιμο ένα καθυστερημένο αντίγραφο (και πού όχι)

Χρησιμοποιήστε την καθυστερημένη αναπαραγωγή ως πρώτη βοήθεια εάν χάσετε κατά λάθος δεδομένα και παρατηρήσετε αυτήν την καταστροφή εντός της ρυθμισμένης καθυστέρησης.

Αλλά να έχετε κατά νου: η αναπαραγωγή δεν είναι αντίγραφο ασφαλείας.

Η δημιουργία αντιγράφων ασφαλείας και η αναπαραγωγή έχουν διαφορετικούς σκοπούς. Ένα κρύο αντίγραφο ασφαλείας θα σας φανεί χρήσιμο εάν το δημιουργήσατε κατά λάθος DELETE ή DROP TABLE. Δημιουργούμε ένα αντίγραφο ασφαλείας από την ψυχρή αποθήκευση και επαναφέρουμε την προηγούμενη κατάσταση ενός πίνακα ή μιας ολόκληρης βάσης δεδομένων. Αλλά ταυτόχρονα και το αίτημα DROP TABLE αναπαράγεται σχεδόν αμέσως σε όλα τα αντίγραφα στο σύμπλεγμα εργασίας, επομένως η κανονική αναπαραγωγή δεν θα αποθηκευτεί εδώ. Η ίδια η αναπαραγωγή διατηρεί τη βάση δεδομένων διαθέσιμη όταν μεμονωμένοι διακομιστές μισθώνονται και διανέμει το φορτίο.

Ακόμη και με καθυστερημένο αντίγραφο, μερικές φορές χρειαζόμαστε πραγματικά ένα κρύο αντίγραφο ασφαλείας σε ασφαλές μέρος, εάν ξαφνικά υπάρξει βλάβη στο κέντρο δεδομένων, κρυφή ζημιά ή άλλα συμβάντα που δεν παρατηρείτε αμέσως. Εδώ από μια αναπαραγωγή δεν έχει νόημα.

Σημείωση. επί GitLab.com Προς το παρόν προστατεύουμε από απώλεια δεδομένων μόνο σε επίπεδο συστήματος και δεν επαναφέρουμε δεδομένα σε επίπεδο χρήστη.

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο