التعمق في النسخ المتماثل
التعمق في النسخ المتماثل
النسخ المتماثل هو العمود الفقري لتوافر قواعد البيانات العالي وتوسع القراءة الأفقي، وهو في الوقت ذاته أحد أخصب مصادر حوادث الإنتاج. فهم النسخ المتماثل على مستوى البروتوكول، لا مجرد اعتباره ميزة تُفعّل وتُنسى، يُميّز المهندسين الذين يديرون قواعد البيانات عن أولئك الذين تديرهم قواعد البيانات.
كيف يعمل النسخ المتماثل فعلاً
يعتمد كل من MySQL/MariaDB وPostgreSQL على النسخ المتماثل القائم على سجل ثنائي (binlog / WAL). يكتب الخادم الأساسي (Primary) كل تغيير مُنفَّذ في سجل دائم. تقوم النسخ المتماثلة (Replicas) بدفق هذا السجل وإعادة تنفيذه بالترتيب. النقطة الجوهرية هنا أن هذه العملية غير متزامنة (Async) بشكل افتراضي: يعتبر الخادم الأساسي المعاملة مُكتملة فور كتابتها على قرصه، قبل أن تُقرّ أي نسخة باستلامها.
تأخر النسخ المتماثل: الأسباب والقياس والحدود
تأخر النسخ المتماثل (Replication Lag) هو عمر أقدم حدث غير منفَّذ على نسخة ما. ليس رقماً واحداً بل هو محصلة: زمن استجابة الشبكة، واختناق الإدخال/الإخراج على النسخة، وعقبات إعادة التشغيل أحادية الخيط (قبل MySQL 8.0 وقبل تطبيق التوازي في Postgres).
أسباب التأخر الشائعة على نطاق واسع:
- المعاملات الضخمة — استعلام
UPDATE orders SET ... WHERE 1=1الذي يستغرق 40 ثانية على الخادم الأساسي يُعطّل خيط SQL على النسخة لنفس المدة. - إعادة التشغيل المقيّدة بالإدخال/الإخراج — تعمل النسخ غالباً على أجهزة أرخص، فيصبح القرص عنق الزجاجة.
- جمل DDL —
ALTER TABLEعلى جدول بحجم 200 GB تُقفل خيط SQL طوال مدة تنفيذها على النسخ المعتمدة على الصف. - خيط SQL أحادي — MySQL قبل 5.7 وPostgres قبل التطبيق الموازي في النسخ المنطقية للإصدار 16. فعّل خيوط SQL المتوازية.
قس التأخر من داخل قاعدة البيانات لا من نبضات جانب التطبيق:
في Prometheus، أظهر هذه المقاييس عبر mysqld_exporter أو postgres_exporter وأطلق تنبيهات عند تجاوز التأخر حد مستوى خدمتك (عادةً 30 ثانية لـ OLTP، و5 دقائق لنسخ التحليلات):
replica_parallel_workers = 8 وreplica_parallel_type = LOGICAL_CLOCK في /etc/mysql/conf.d/replica.cnf. يتيح هذا إعادة تشغيل المعاملات المستقلة بالتوازي، مما يقلل التأخر 4 إلى 8 أضعاف على أحمال الكتابة الكثيفة. تحقق من النتيجة عبر SHOW PROCESSLIST — يجب أن ترى عدة خيوط system user تُنفّذ SQL.نسخ القراءة في الإنتاج: الأنماط والمزالق
نسخ القراءة قوية — إذ تستوعب 80-95% من حركة المرور في الخدمات كثيفة القراءة. قواعد استخدامها بأمان:
- لا تقرأ بياناتك الخاصة من نسخة بعد الكتابة. بعد الكتابة على الخادم الأساسي، وجّه القراءة التالية لتلك الجلسة إلى الخادم الأساسي (أو انتظر
WAIT_FOR_EXECUTED_GTID_SET/pg_wal_replay_wait()للتأكد من لحاق النسخة). الارتباط بالخادم الأساسي بعد الكتابة هو النمط الأكثر أماناً. - وجّه حسب نوع الاستعلام لا عشوائياً. استعلامات التحليلات تنتمي إلى نسخة مخصصة؛ قراءات OLTP تستطيع استخدام مجموعة نسخ عامة. لا تخلطهما — استعلام تحليلي لمدة 60 ثانية سيُؤخر إعادة تشغيل OLTP خلفه.
- استخدم وكيلاً (Proxy). ProxySQL لـ MySQL وPgBouncer+HAProxy لـ Postgres يديران التوجيه للقراءة/الكتابة والفحوصات الصحية والتحويل التلقائي دون تضمين سلاسل الاتصال في كود التطبيق.
- افحص التأخر قبل التوجيه.
mysql_servers.max_replication_lagفي ProxySQL يزيل خادماً من مجموعة القراءة عند تجاوز التأخر الحد. اضبط هذا. نسخة متأخرة ببيانات قديمة أسوأ من توجيه القراءة للخادم الأساسي.
الانفصال الدماغي (Split-Brain): أخطر أنماط الفشل
يحدث الانفصال الدماغي عندما يعتقد عقدتان في آنٍ واحد أن كلاً منهما هو الخادم الأساسي وتقبلان الكتابة. كلتاهما تتباعدان. حين يُشفى انقطاع الشبكة، لديك تاريخان متعارضان لا طريقة آلية لدمجهما. البيانات ضائعة.
استراتيجيات الوقاية (مرتبة حسب الفعالية):
- STONITH / العزل (Fencing) — اختصار لـ "أطلق النار على العقدة الأخرى في رأسها". قبل أن تُرقّي النسخة نفسها، يجب أن تعزل الخادم الأساسي القديم (إيقاف تشغيله عبر IPMI، أو فصل قرصه السحابي، أو إنهاء واجهة شبكته). دون عزل، يستطيع عقدتان الاعتقاد في آنٍ واحد أنهما خادم أساسي.
- الترقية المبنية على الحصة النسبية (Quorum) — تشترط كل من Patroni (Postgres) وOrchestrator (MySQL) وMHA تصويت أغلبية الكتلة قبل الترقية. الأقلية المعزولة لا تستطيع تحقيق الحصة، فلا تستطيع الترقية.
- النسخ شبه المتزامن — يشترط تأكيد نسخة واحدة على الأقل قبل إعادة الخادم الأساسي للنجاح. إذا كانت جميع النسخ غير متاحة، يعود شبه المتزامن إلى وضع غير متزامن بعد
rpl_semi_sync_source_timeout(الافتراضي 10 ثوانٍ) — يتدهور بأمان لكنه يمنع أكثر سيناريوهات فقدان البيانات شيوعاً. - مراقبة ضغط فتحات النسخ في Postgres — الفتحات غير المستخدمة تحتجز WAL إلى أجل غير مسمى. نسخة تتأخر كثيراً ثم تعود ستتسبب في نفاد ذاكرة الخادم الأساسي. راقب
pg_replication_slots.activeوأسقط الفتحات غير النشطة فوراً.
max_wal_size = 1GB وبدون فتحات نسخ — ما يعني إعادة تدوير WAL قبل أن تتمكن نسخة بطيئة من إعادة تشغيله. فعّل فتحات النسخ للنسخ التي تهتم بها، لكن اضبط max_slot_wal_keep_size لتحديد سقف الاحتفاظ بـ WAL حتى لا تملأ النسخة الميتة القرص. بدون هذا السقف، نسخة تنقطع لمدة 24 ساعة قادرة على إسقاط الخادم الأساسي حين ينفد تخزين WAL.قائمة مراجعة التشغيل: تشغيل النسخ في الإنتاج
- فعّل النسخ المتماثل المبني على GTID (
gtid_mode=ON+enforce_gtid_consistency=ONفي MySQL) حتى لا يتطلب التحويل الحسابَ اليدوي لموضع binlog. - راقب
Seconds_Behind_Sourceأوpg_replication_lagمع تنبيهات؛ أطلق تنبيه الاستدعاء عند تأخر يتجاوز 60 ثانية. - اضبط
read_only=ONعلى كل نسخة على مستوى المحرك — يجب أن يضبط مدير الـ HA أيضاًsuper_read_only=ONحتى لا يتمكن حتى المستخدمون المميزون من الكتابة عن طريق الخطأ. - تحقق من سلامة النسخ أسبوعياً باستخدام
pt-table-checksum(MySQL) أوpg_amcheck(Postgres 14+). الفساد الصامت حقيقي. - اختبر التحويل في بيئة تجريبية شهرياً. متوسط وقت التأكيد من أن مكدس الـ HA يعمل فعلاً أقيم من أي دليل تشغيل.