قواعد البيانات والتخزين

النسخ المتماثل لقواعد البيانات

18 دقيقة الدرس 5 من 10

النسخ المتماثل لقواعد البيانات

خادم قاعدة البيانات الواحد هو نقطة فشل وحيدة. إذا تعطّل هذا الجهاز، تتوقف خدمتك بالكامل. حتى قبل وقوع الأعطال، ثمة سقف صلب لعدد استعلامات القراءة التي يستطيع الخادم الواحد معالجتها — كل استعلام وتقرير تحليلي ومهمة خلفية تتنافس على نفس المعالج والذاكرة والإدخال/الإخراج. النسخ المتماثل (Replication) هو ممارسة الاحتفاظ بنسخ متزامنة من بياناتك على خوادم متعددة، مما يحل المشكلتين في آنٍ واحد: يُزيل نقطة الفشل الوحيدة ويوزع حِمل القراءة على أجهزة متعددة.

فهم النسخ المتماثل بعمق — ولا سيما المقايضات بين الأنماط المتزامنة وغير المتزامنة — أمر ضروري لكل مهندس يصمم أنظمة يجب أن تتمتع بالتوافر العالي والاتساق معًا.

نسخ القائد-التابع (Leader-Follower)

أكثر طوبولوجيات النسخ المتماثل شيوعًا هي القائد-التابع (تُعرف أيضًا بـ Primary-Replica أو Master-Slave). القواعد بسيطة:

  • عقدة واحدة تُعيَّن قائدًا (Leader/Primary). تذهب جميع عمليات الكتابة إلى القائد — فهو المصدر الوحيد الموثوق للحقيقة.
  • عقدة أو أكثر تكون تابعة (Followers/Replicas). تتلقى نسخة من كل عملية كتابة من القائد وتطبّقها على تخزينها الخاص. يستقبل التابعون استعلامات القراءة.
  • يوجّه العملاء عمليات الكتابة إلى القائد وعمليات القراءة إلى أي تابع (أو القائد، حسب احتياجات الاتساق).

يُستخدم هذا النموذج في النسخ المتدفق لـ PostgreSQL، ونسخ السجل الثنائي لـ MySQL، ومجموعات replica في MongoDB (في وضع primary-secondary)، ومعظم قواعد البيانات المُدارة (قواعد بيانات AWS RDS read replicas، وGoogle Cloud SQL، وغيرها).

Leader-follower replication topology Application Write & Read clients Leader (Primary) Accepts all WRITEs WRITE Follower 1 Read Replica Follower 2 Read Replica Follower 3 Read Replica replicate replicate replicate READ READ
طوبولوجيا القائد-التابع: تذهب جميع عمليات الكتابة إلى القائد الوحيد؛ تستقبل التوابع تدفق التغييرات وتخدم استعلامات القراءة.

كيف يعمل النسخ المتماثل داخليًا

عند إتمام عملية كتابة على القائد، تسجّلها قاعدة البيانات في سجل النسخ المتماثل (يُسمى Write-Ahead Log في PostgreSQL، أو السجل الثنائي في MySQL). يبث القائد إدخالات السجل إلى كل تابع. يطبق كل تابع هذه الإدخالات بالترتيب، ليمتلك في النهاية نسخة متطابقة من البيانات.

السؤال الجوهري الذي يجب أن تجيب عنه كل منظومة نسخ متماثل هو: متى يعتبر القائد عملية الكتابة "مكتملة"؟ ومن هنا ينشأ الوضعان الأساسيان.

النسخ المتماثل المتزامن (Synchronous)

في الوضع المتزامن، ينتظر القائد تأكيدًا من تابع واحد على الأقل قبل تأكيد الكتابة للعميل. لا تعتبر عملية الكتابة مكتملة حتى يخزّن التابع البيانات بشكل دائم.

الضمان: إذا تعطّل القائد فور تأكيد الكتابة، فإن تابعًا واحدًا على الأقل يمتلك تلك البيانات. لا تُفقد أي كتابة مُؤكَّدة أبدًا.

التكلفة: يجب أن تُكمل كل عملية كتابة رحلة شبكية ذهابًا وإيابًا إلى التابع قبل أن يحصل العميل على استجابة. إذا كان القائد والتابع في نفس مركز البيانات، يُضاف 1-5 ميلي ثانية. عبر المناطق، يُضاف 50-200 ميلي ثانية — وهذا التأخير على المسار الحرج لكل عملية كتابة.

النسخ المتماثل المتزامن قد يوقف الكتابة كليًا. إذا انقطع التابع المتزامن أو أصبح بطيئًا، لا يستطيع القائد تأكيد أي كتابة حتى يتعافى ذلك التابع. لهذا السبب تُعيّن معظم أنظمة الإنتاج تابعًا متزامنًا واحدًا على الأكثر وتجعل البقية غير متزامنة — هو الإعداد الذي يسميه PostgreSQL "synchronous_standby_names = 1".

النسخ المتماثل غير المتزامن (Asynchronous)

في الوضع غير المتزامن، يؤكد القائد الكتابة للعميل فور كتابتها على قرصه المحلي. يشحن التغيير إلى التوابع في الخلفية — لا ينتظر العميل أبدًا تأكيدات التوابع.

الفائدة: تأخير الكتابة منخفض كما في قاعدة بيانات مفردة. أعطال التوابع لا تعيق القائد أبدًا. هذا الوضع هو الافتراضي في نسخ MySQL وقواعد بيانات AWS RDS read replicas.

التكلفة: إذا تعطّل القائد بعد تأكيد الكتابة للعميل لكن قبل إرسالها للتوابع، تُفقد تلك الكتابة. يُسمى هذا تأخر النسخ المتماثل (Replication Lag)، ويُفضي إلى مخاطرة باتساق البيانات: قد يكتب العميل بيانات إلى القائد ثم يقرأ من تابع لم يطبّق تلك الكتابة بعد، فيرى بيانات قديمة.

تأخر النسخ المتماثل ليس خللًا، بل خيار تصميمي. في ظروف عادية يكون التوابع غير المتزامنة متأخرة بضعة ميلي ثوانٍ فقط. لكن تحت حِمل كتابة مرتفع أو شبكة بطيئة، قد يتراكم التأخير إلى ثوانٍ أو حتى دقائق. قِس دائمًا تأخر النسخ المتماثل في الإنتاج (مثل pg_stat_replication.write_lag في PostgreSQL أو Seconds_Behind_Source في MySQL) وأصدر تنبيهات عند تجاوز حد التحمل.

مقارنة جنبًا إلى جنب: المتزامن مقابل غير المتزامن

Synchronous vs asynchronous replication sequence diagrams Synchronous Replication Client Leader Follower 1. Write Request Write to disk 2. Replicate WAL Persist 3. ACK 4. Confirm to client المتانة: قوية لا تُفقد بيانات مُؤكَّدة عند عطل القائد التأخير: أعلى (+رحلة شبكية) عطل التابع يوقف جميع عمليات الكتابة Asynchronous Replication Client Leader Follower 1. Write Request Write disk 2. Confirm immediately 3. Async WAL (background) Persist التأخير: منخفض (سرعة خادم منفرد) عطل التابع لا يعيق عمليات الكتابة المتانة: أضعف قد تُفقد كتابات عند عطل القائد
مقارنة بين النسخ المتزامن وغير المتزامن: المتزامن ينتظر تأكيد التابع قبل الرد على العميل؛ غير المتزامن يؤكد فورًا ويشحن السجل في الخلفية.

الفشل والترقية (Failover and Promotion)

عند فشل القائد، يجب ترقية أحد التوابع ليصبح القائد الجديد. تُسمى هذه العملية الاستبدال عند الفشل (Failover). تعتمد سلاسة هذه العملية على وضع النسخ المتماثل:

  • مع النسخ المتزامن: التابع المُرقَّى مضمون أن يمتلك كل عملية كتابة مُؤكَّدة. الاستبدال نظيف وفقدان البيانات صفر.
  • مع النسخ غير المتزامن: قد يكون التابع متأخرًا قليلًا. تُفقد أي كتابات أكدها القائد للعملاء لكن لم يرسلها للتوابع بعد. تقبل معظم قواعد البيانات المُدارة (RDS وCloud SQL) هذه المقايضة لأن نافذة فقدان الكتابة في الظروف العادية تكون أقل من ثانية.

بعد الترقية، يجب إعادة تهيئة التوابع القديمة لتتبع القائد الجديد. في أنظمة مثل PostgreSQL Patroni أو MySQL Orchestrator، تكون هذه الإعادة تلقائية.

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

توسيع القراءة واتساق "اقرأ ما كتبته"

من الفوائد الرئيسية للتوابع هو توسيع القراءة (Read Scaling): يمكنك إضافة توابع لاستيعاب حركة قراءة أكبر دون المساس بالقائد. قائد واحد مع خمسة توابع يستطيع خدمة 5 أضعاف استعلامات القراءة مقارنةً بخادم منفرد، بينما تبقى الكتابات على القائد.

ومع ذلك، يُقدّم هذا مشكلة اتساق خفية. افترض أن مستخدمًا حدّث صورة ملفه الشخصي. ذهبت الكتابة إلى القائد. بعد ميلي ثانية أعاد المستخدم تحميل الصفحة — لكن توجّهت القراءة إلى تابع لم يطبّق الكتابة بعد. يرى المستخدم صورته القديمة. يُسمى هذا الانتهاك القراءة القديمة (Stale Read) أو انتهاك اتساق "اقرأ ما كتبته".

الحلول الشائعة:

  • إعادة توجيه القراءات التي كتبها المستخدم الحالي (خلال N ثانية) إلى القائد.
  • تتبع موضع النسخ المتماثل الذي كتبه العميل آخر مرة؛ توجيه القراءات فقط إلى التوابع التي لحقت بذلك الموضع.
  • قبول نافذة تناسق صغيرة للبيانات التي لم يعدّلها المستخدم مباشرةً (مثل تغذية اجتماعية — رؤية منشور متأخرًا بثانية أمر مقبول).

النسخ المتماثل شبه المتزامن

يقدم MySQL حلًا وسطًا يُسمى النسخ المتماثل شبه المتزامن (Semi-Synchronous Replication): ينتظر القائد تأكيدًا من تابع واحد على الأقل بأنه استلم الكتابة (لكن ليس بالضرورة أن يكون قد حفظها على القرص). يُزيل هذا فقدان البيانات عند عطل القائد بتكلفة تأخير أقل من النسخ المتزامن الكامل، مع ضمان مغادرة البيانات لجهاز القائد.

ملخص

النسخ المتماثل للقائد-التابع هو النمط الأساسي لتحقيق التوافر العالي وتوسيع القراءة في قواعد البيانات. القائد هو سلطة الكتابة الوحيدة؛ التوابع تبث سجل النسخ المتماثل وتخدم القراءات. المقايضة الجوهرية بين الوضع المتزامن — الذي يضمن عدم فقدان أي كتابة مُؤكَّدة عند الاستبدال لكن يُضيف تأخيرًا شبكيًا لكل كتابة — والوضع غير المتزامن — الذي يوفر كتابة بتأخير منخفض على حساب نافذة محتملة لفقدان البيانات والاتساق التدريجي في القراءة. في الممارسة العملية، تستخدم معظم الأنظمة واسعة النطاق النسخ غير المتزامن افتراضيًا وتُضيف تقنيات تعويضية (توجيه، تتبع موضع النسخ) لتحقيق اتساق مقبول لحالات الاستخدام المختلفة.