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


ما هو التكرار المؤجل؟


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


يحتوي PostgreSQL على طريقتين لتكوين النسخة المتماثلة الفعلية لقاعدة البيانات: الاستعادة من الأرشفة وتكرار البث. في الواقع ، تعمل الاستعادة من الأرشيف ، مثل PITR ، ولكن بشكل مستمر: نستخرج باستمرار التغييرات من أرشيف WAL ونطبقها على النسخة المتماثلة. وتدفق النسخ المتماثل مباشرة باسترداد دفق WAL من مضيف قاعدة البيانات upstream. نحن نفضل الاسترداد من الأرشيف - من الأسهل إدارته ولديه أداء عادي ، والذي لا يتخلف عن مجموعة العمل.


كيفية إعداد الانتعاش المؤجل من الأرشيف


يتم وصف خيارات الاسترداد في ملف recovery.conf . مثال:


 standby_mode = 'on' restore_command = '/usr/bin/envdir /etc/wal-ed/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 بتطبيق الاسترداد المؤجل. دعونا نلقي نظرة على 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 لإغلاق مثيل أو تقدمه أو إيقافه مؤقتًا بعد إعادة التشغيل (بشكل افتراضي ، يتوقف مؤقتًا).


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


بدلاً من الطوابع الزمنية ، من الأفضل استخدام معرفات المعاملات. من المفيد كتابة هذه المعرفات ، على سبيل المثال ، log_statements = 'ddl' DDL (مثل DROP TABLE ) ، باستخدام log_statements = 'ddl' . إذا كان لدينا معرّف معاملة ، فسنأخذ 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 ، نحن الآن نحمي من فقدان البيانات فقط على مستوى النظام ولا نستعيد البيانات على مستوى المستخدم.

Source: https://habr.com/ru/post/ar445446/


All Articles