كيف استخدمنا النسخ المتماثل الكسول للتعافي من الكوارث باستخدام PostgreSQL

كيف استخدمنا النسخ المتماثل الكسول للتعافي من الكوارث باستخدام PostgreSQL
النسخ المتماثل ليس نسخة احتياطية. أم لا؟ إليك كيفية استخدام النسخ المتماثل البطيء للاسترداد عن طريق حذف الاختصارات عن طريق الخطأ.

متخصصو البنية التحتية GitLab هو المسؤول عن العمل جيتلاب.كوم - أكبر مثال على GitLab في الطبيعة. مع 3 ملايين مستخدم وما يقرب من 7 ملايين مشروع ، فهي واحدة من أكبر مواقع SaaS مفتوحة المصدر مع بنية مخصصة. بدون نظام قاعدة بيانات PostgreSQL ، لن تذهب البنية التحتية لـ GitLab.com بعيدًا ، وما لا نفعله للتسامح مع الأخطاء في حالة حدوث أي إخفاقات عندما تفقد البيانات. من غير المحتمل أن تحدث مثل هذه الكارثة ، لكننا استعدنا جيدًا وقمنا بتخزين العديد من آليات النسخ الاحتياطي والتكرار.

النسخ المتماثل ليس أداة النسخ الاحتياطي لقاعدة البيانات الخاصة بك (انظر أدناه). ولكن الآن سنرى كيفية استرداد البيانات المحذوفة عن طريق الخطأ بسرعة باستخدام النسخ المتماثل البطيء: on جيتلاب.كوم المستخدم الاختصار الذي تمت إزالته للمشروع gitlab-ce وفقد الاتصال بطلبات ومهام الدمج.

مع النسخة المتماثلة المتأخرة ، استعدنا البيانات في 1,5 ساعة فقط. انظر كيف كان.

الاسترداد الفوري مع PostgreSQL

تحتوي PostgreSQL على وظيفة مضمنة تعيد حالة قاعدة البيانات إلى نقطة زمنية محددة. تسمى نقطة في الوقت الانتعاش (PITR) ويستخدم نفس الآليات التي تحافظ على تحديث النسخة المتماثلة: بدءًا من لقطة موثوقة لمجموعة قاعدة البيانات بأكملها (النسخ الاحتياطي الأساسي) ، نطبق سلسلة من تغييرات الحالة حتى نقطة زمنية معينة.

لاستخدام هذه الميزة للنسخ الاحتياطي البارد ، نقوم بانتظام بعمل نسخة احتياطية أساسية لقاعدة البيانات وتخزينها في أرشيف (توجد أرشيفات GitLab في جوجل سحابة التخزين). نراقب أيضًا تغييرات حالة قاعدة البيانات من خلال أرشفة سجل الكتابة المسبقة (الكتابة مسبقا سجل، WAL). ومع كل هذا ، يمكننا إجراء PITR للتعافي من الكوارث: نبدأ بلقطة التقطت قبل الخطأ ونطبق التغييرات من أرشيف WAL حتى الانهيار.

ما هو تأخر التكرار؟

النسخ المتماثل المتأخر هو تطبيق التغييرات من WAL مع تأخير. أي أن الصفقة تمت على مدار الساعة X، لكنها ستظهر في النسخة المتماثلة مع تأخير d في الوقت المحدد X + d.

هناك طريقتان لإعداد نسخة طبق الأصل من قاعدة البيانات الفعلية في 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). ستراقب النسخة المتماثلة تغييرات المخطط الزمني في الأرشيف ، على سبيل المثال بسبب تجاوز فشل مجموعة (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لإغلاق المثيل أو ترقيته أو إيقافه مؤقتًا بعد إعادة المحاولة (يتوقف بشكل افتراضي).

وصلت قاعدة البيانات إلى الدولة قبل هذا الطلب المشؤوم. يمكنك الآن ، على سبيل المثال ، تصدير البيانات. لقد قمنا بتصدير بيانات التسمية البعيدة وجميع الروابط المؤدية إلى المشكلات وطلبات الدمج ونقلها إلى قاعدة بيانات الإنتاج. إذا كانت الخسائر كبيرة ، يمكنك ببساطة ترقية النسخة المتماثلة واستخدامها كخيار رئيسي. ولكن بعد ذلك ستفقد كل التغييرات بعد اللحظة التي تعافينا فيها.

من الأفضل استخدام معرفات المعاملات بدلاً من الطوابع الزمنية. من المفيد تسجيل هذه المعرفات ، على سبيل المثال ، لعبارات DDL (مثل DROP TABLE)، باستخدام log_statements = 'ddl'. إذا كان لدينا معرّف معاملة ، فسنأخذها recovery_target_xid وتشغيل كل شيء وصولاً إلى المعاملة قبل الطلب DELETE.

تعد العودة إلى العمل أمرًا بسيطًا للغاية: قم بإزالة جميع التغييرات من recovery.conf وإعادة تشغيل postgres. وسرعان ما سيتأخر العلاج مرة أخرى لمدة ثماني ساعات ، ونحن مستعدون لمواجهة أي مشاكل في المستقبل.

فوائد الانتعاش

مع النسخة المتماثلة المتأخرة ، بدلاً من النسخ الاحتياطي البارد ، لن تضطر إلى قضاء ساعات في استعادة اللقطة بأكملها من الأرشيف. على سبيل المثال ، نحتاج إلى خمس ساعات للحصول على النسخة الاحتياطية الكاملة لقاعدة 2 تيرابايت. وبعد ذلك لا يزال يتعين عليك تطبيق WAL اليومي بالكامل للتعافي إلى الحالة المطلوبة (في أسوأ الحالات).

النسخة المتماثلة المتأخرة أفضل من النسخ الاحتياطي البارد بطريقتين:

  1. لا تحتاج إلى الحصول على النسخة الاحتياطية الأساسية بالكامل من الأرشيف.
  2. هناك نافذة ثابتة مدتها ثماني ساعات من مقاطع WAL التي يجب تكرارها.

أيضًا ، نحن نتحقق باستمرار لمعرفة ما إذا كان WAL يمكن أن يكون PITRed ، وسنلاحظ بسرعة تلفًا أو مشاكل أخرى في أرشيف WAL من خلال مراقبة تراكم النسخة المتماثلة المتأخرة.

في هذا المثال ، استغرق الأمر منا 50 دقيقة للاستعادة ، أي أن السرعة كانت 110 جيجابايت من بيانات WAL في الساعة (كان الأرشيف لا يزال قيد التشغيل أوس S3). في المجموع ، قمنا بحل المشكلة واستعدنا البيانات في 1,5 ساعة.

ملخص: حيث تكون النسخة المتماثلة المؤجلة مفيدة (وحيث لا تكون كذلك)

استخدم النسخ المتماثل المتأخر كإسعافات أولية إذا فقدت البيانات عن طريق الخطأ ولاحظت هذه الكارثة خلال التأخير الذي تم تكوينه.

لكن ضع في اعتبارك: النسخ المتماثل ليس نسخة احتياطية.

النسخ الاحتياطي والنسخ له أغراض مختلفة. سيكون النسخ الاحتياطي البارد مفيدًا إذا قمت بعمله عن طريق الخطأ DELETE أو DROP TABLE. نقوم بعمل نسخة احتياطية من التخزين البارد واستعادة الحالة السابقة لجدول أو قاعدة بيانات كاملة. لكن في نفس الوقت الطلب DROP TABLE يتم استنساخه على الفور تقريبًا في جميع النسخ المتماثلة الموجودة على مجموعة العمل ، لذلك لن يتم حفظ النسخ المتماثل المنتظم هنا. النسخ المتماثل نفسه يحافظ على قاعدة البيانات متاحة عندما يتم تأجير الخوادم الفردية وتوزيع الحمل.

حتى مع وجود نسخة متماثلة متأخرة ، نحتاج في بعض الأحيان حقًا إلى نسخة احتياطية باردة في مكان آمن ، إذا حدث فجأة عطل في مركز البيانات أو تلف خفي أو أحداث أخرى لا تلاحظها على الفور. هنا من تكرار واحد لا معنى له.

لاحظ. في جيتلاب.كوم نحن نحمي حاليًا فقط من فقدان البيانات على مستوى النظام ولا نستعيد البيانات على مستوى المستخدم.

المصدر: www.habr.com

إضافة تعليق