قواعد البيانات في الإنتاج

معماريات التوفر العالي

22 دقيقة الدرس 2 من 30

معماريات التوفر العالي

قاعدة البيانات التي تتوقف تُسقط معها المنتج بأكمله. كل طبقة أخرى في المكدس — موازنات الأحمال وخوادم التطبيقات وشبكات توصيل المحتوى — يمكن جعلها عديمة الحالة واستبدالها في ثوانٍ. قواعد البيانات لا يمكن ذلك. هي تملك الحالة، وفقدانها يعني فقدان بيانات المستخدم وتاريخ المعاملات وكثيراً ما يعني فقدان العمل بأكمله. معمارية التوفر العالي (HA) هي مجموعة الأنماط التي تجعل مجموعة قواعد البيانات تتحمل إخفاقات العقد وتقسيمات الشبكة وانقطاعات منطقة التوفر دون تدخل بشري. يُغطي هذا الدرس الركائز الثلاث للتوفر العالي في الإنتاج: طوبولوجيا التكرار، ومقايضات التكرار المتزامن مقابل غير المتزامن، والتحويل التلقائي عند الإخفاق.

نموذج الأساسي/النسخة المتماثلة

النمط الأساسي للتوفر العالي في قواعد البيانات العلائقية هو التكرار بين الأساسي والنسخة المتماثلة (Primary/Replica) (يُسمى تاريخياً master/slave). عقدة واحدة — الأساسية — تقبل جميع عمليات الكتابة. عقدة واحدة أو أكثر من النسخ المتماثلة تستقبل تدفقاً من التغييرات من الأساسي وتُعيد تشغيلها للحفاظ على نسخة متطابقة من البيانات.

يُعطيك هذا الفصل ثلاثة أشياء في وقت واحد:

  • التكرار: إذا مات الأساسي، يمكن ترقية نسخة متماثلة لتحل محله.
  • قابلية التوسع في القراءة: أحمال عمل القراءة الكثيفة يمكنها توزيع استعلامات SELECT عبر النسخ المتماثلة، مما يُخفّف ضغط الكتابة على الأساسي.
  • السلامة التشغيلية: استعلامات التحليلات الطويلة تعمل على نسخة متماثلة دون إبطاء عمليات الكتابة التشغيلية على الأساسي.
الفكرة الأساسية: نموذج الأساسي/النسخة المتماثلة ليس استراتيجية نسخ احتياطي — إنه استراتيجية تحويل عند الإخفاق. النسخة المتماثلة التي تتأخر 30 ثانية عن الأساسي لا يمكنها استبدال نسخة احتياطية مأخوذة قبل أمر DROP TABLE المدمر. التكرار والنسخ الاحتياطي يحلان أنماط إخفاق مختلفة وكلاهما مطلوب في الإنتاج.

في PostgreSQL، يُبنى التكرار على بث سجل الكتابة المسبقة (WAL Streaming). كل معاملة على الأساسي تُكتب أولاً في WAL؛ تتصل النسخ المتماثلة كعملاء بث التكرار وتستقبل مقاطع WAL في شبه وقت فعلي. في MySQL/MariaDB، المكافئ هو سجل الثنائيات (binlog) المُبثّ بتنسيق قائم على الصفوف. كلا الآليتين تعنيان أن النسخ المتماثلة لا تقرأ مباشرة من جداول الأساسي — إنها تُعيد تشغيل سجل التغييرات، مما يجعل التكرار خفيفاً حتى عند معدلات كتابة عالية.

التكرار المتزامن مقابل غير المتزامن

أهم قرار معماري في التوفر العالي لقواعد البيانات هو ما إذا كان التكرار متزامناً أم غير متزامن. هذا ليس تفضيلاً — إنه مقايضة مباشرة بين ضمانات المتانة وزمن استجابة الكتابة، والاختيار الخاطئ يُسبب فقدان البيانات أو إبطاء مقبول.

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

التكرار المتزامن: يكتب الأساسي إلى WAL ولا يُقرّ بتنفيذ العميل إلا بعد أن تؤكد نسخة متماثلة متزامنة محددة على الأقل أنها استلمت إدخال WAL وحوّلته إلى تخزين دائم. لا يمكن فقدان أي بيانات عند التحويل إلى تلك النسخة المتماثلة. التكلفة: كل عملية كتابة تتحمل رحلة شبكة إضافية إلى النسخة المتماثلة — عادةً 0.5–2 مللي ثانية في نفس منطقة التوفر، و5–30 مللي ثانية عبر مناطق التوفر. عند معدلات كتابة عالية (آلاف المعاملات في الثانية)، يتراكم هذا الزمن.

مصيدة إنتاجية — وهم المتانة: كثير من الفرق تُشغّل تكراراً غير متزامن وتعتقد أن لديها توفراً عالياً لأن لديها نسخة متماثلة. ليس لديها. إذا تعطل الأساسي والنسخة المتماثلة تتأخر 10 ثوانٍ، فقدت للتو 10 ثوانٍ من المعاملات المُنفَّذة. للأنظمة المالية وإدخال الطلبات وأي كتابة تلقّى المستخدم بالفعل "نجاح" لها، هذا كارثي. استخدم التكرار المتزامن على نسخة متماثلة واحدة على الأقل لكل حمل عمل حيث تكون متانة البيانات المُنفَّذة متطلباً صارماً.

الحل الصناعي في شركات مثل Google (Spanner, AlloyDB) وAWS (Aurora) هو استخدام بروتوكول كتابة قائم على النصاب القانوني يحقق متانة متزامنة عبر عقد متعددة بينما يُخفي معظم عقوبة زمن الاستجابة. Aurora مثلاً تكتب سجل السجل إلى 6 عقد تخزين عبر 3 مناطق توفر وتُقرّ بالتنفيذ بعد أن تؤكد 4 من 6 — يوفر هذا ضمانات متزامنة مع توافر أفضل بكثير من نسخة متماثلة متزامنة واحدة.

بالنسبة لـ PostgreSQL تحديداً، يمكنك ضبط تنفيذ متزامن على مستوى الجلسة أو الخادم:

-- postgresql.conf: اجعل نسخة متماثلة واحدة متزامنة synchronous_standby_names = 'FIRST 1 (replica1, replica2)' synchronous_commit = on -- الافتراضي؛ اضبط على 'remote_write' للحل الوسط -- تجاوز على مستوى الجلسة (مفيد للتحميل الجماعي الذي يتحمل التأخر): SET synchronous_commit = off; COPY large_table FROM '/tmp/data.csv'; SET synchronous_commit = on; -- فحص حالة التكرار الحالية من الأساسي: SELECT client_addr, state, sent_lsn, write_lsn, flush_lsn, replay_lsn, (sent_lsn - replay_lsn) AS replication_lag_bytes, sync_state FROM pg_stat_replication;

يوفر MySQL/InnoDB Group Replication ومكونات شبه المتزامنة الإضافية ضوابط مماثلة. في الخدمات المُدارة (RDS Multi-AZ, CloudSQL)، يُضبط وضع المزامنة على مستوى المثيل ويتولى المحرك شحن WAL بشفافية.

التحويل التلقائي عند الإخفاق

وجود نسخة متماثلة دافئة ليس توفراً عالياً. التوفر العالي يتطلب أنه عند إخفاق الأساسي، تُرقَّى نسخة متماثلة لتصبح أساسية تلقائياً — دون أن يستيقظ إنسان في الثالثة صباحاً ليُشغّل pg_ctl promote. التحويل التلقائي هو المُميّز التشغيلي بين نظام به نسخ متماثلة ونظام بتوفر عالي حقيقي.

مكونات نظام التحويل التلقائي في الإنتاج هي:

  1. مراقبة الصحة: وكيل أو حاوية جانبية تستطلع الأساسي باستمرار. نبضة قلب مفقودة وحدها غير كافية — التطبيقات الجيدة تُميّز بين "الأساسي غير متاح من هذه العقدة" و"الأساسي غير متاح من غالبية المجموعة" لتجنب الدماغ المنقسم.
  2. انتخاب القائد / النصاب القانوني: آلية توافق موزعة (عادةً قائمة على Raft أو Paxos — etcd أو ZooKeeper أو توافق مدمج في المحرك) تنتخب بأمان أساسياً جديداً واحداً بالضبط. يمنع متطلب النصاب القانوني عقدتين من ترقية نفسيهما في وقت واحد وقبول كتابات متضاربة.
  3. الترقية: تُرقَّى النسخة المتماثلة الفائزة لتصبح أساسية — يتوقف إعادة تشغيل WAL وتُقبل اتصالات الكتابة.
  4. إعادة التوجيه: طبقة الاتصال (IP افتراضي أو تحويل DNS أو وسيط مثل PgBouncer/ProxySQL) تُعيد توجيه حركة التطبيق إلى الأساسي الجديد. يجب أن تستخدم التطبيقات نقطة نهاية واحدة تشير دائماً إلى الأساسي الحالي — تضمين عناوين IP للنسخ المتماثلة يكسر هذا.
  5. عزل الأساسي القديم (STONITH): يُعزل الأساسي السابق قبل أن يقبل الأساسي الجديد عمليات الكتابة. بدون العزل، يمكن لأساسي توقف مؤقتاً (جمع القمامة، انقطاع الشبكة) ثم عاد، أن يعتقد لفترة أنه لا يزال أساسياً، مما يُسبب نافزة كتابة بدماغ منقسم.
PostgreSQL HA Failover: Primary, Replicas, Patroni/Etcd, and Connection Layer Application single DB endpoint HAProxy / PgBouncer virtual IP / DNS Primary (AZ-1) Writes accepted WAL streaming out Replica 1 (AZ-2) sync standby Read queries Replica 2 (AZ-3) async standby DR / analytics writes reads WAL sync WAL async Patroni + etcd leader election · health checks · fencing On primary failure: Patroni promotes Replica 1, flips HAProxy endpoint
طوبولوجيا التوفر العالي في الإنتاج: الأساسي في AZ-1 يبثّ WAL بشكل متزامن إلى Replica 1 وبشكل غير متزامن إلى Replica 2. يتولى Patroni مع etcd انتخاب القائد والعزل؛ يُعيد HAProxy توجيه نقطة نهاية الكتابة عند التحويل.

Patroni: التحويل التلقائي في الإنتاج لـ PostgreSQL

الحل الأكثر شيوعاً مفتوح المصدر للتوفر العالي في PostgreSQL هو Patroni، المستخدم في الإنتاج في Zalando وGitLab وAiven وكثيرين آخرين. يعمل Patroni كحاوية جانبية على كل عقدة PostgreSQL ويستخدم etcd (أو Consul أو ZooKeeper) كمخزن توافق موزع للاحتفاظ بقفل قائد المجموعة. العقدة التي تحمل القفل هي الأساسية؛ وجميع الأخريات نسخ متماثلة. تبدو إعدادات Patroni البسيطة هكذا:

# /etc/patroni/config.yml (العقدة: pg-node-1) scope: prod-postgres-cluster name: pg-node-1 restapi: listen: 0.0.0.0:8008 connect_address: 10.0.1.11:8008 etcd3: hosts: 10.0.1.50:2379,10.0.1.51:2379,10.0.1.52:2379 bootstrap: dcs: ttl: 30 # مهلة قفل القائد بالثواني loop_wait: 10 # فاصل فحص الصحة retry_timeout: 10 maximum_lag_on_failover: 1048576 # 1 ميغابايت — ارفض الترقية إذا تجاوز التأخر هذا synchronous_mode: true # اشترط نسخة متماثلة متزامنة واحدة على الأقل قبل التنفيذ initdb: - encoding: UTF8 - data-checksums postgresql: listen: 0.0.0.0:5432 connect_address: 10.0.1.11:5432 data_dir: /var/lib/postgresql/14/main bin_dir: /usr/lib/postgresql/14/bin parameters: wal_level: replica max_wal_senders: 5 max_replication_slots: 5 hot_standby: "on" synchronous_commit: "on" synchronous_standby_names: "FIRST 1 (*)" tags: nofailover: false noloadbalance: false clonefrom: false nosync: false

مع ضبط maximum_lag_on_failover، يرفض Patroni ترقية نسخة متماثلة تخلفت كثيراً — مما يمنع ترقية عقدة قديمة تُلغي معاملات مُنفَّذة. مزيج synchronous_mode: true وحد تأخر منخفض يمنحك ضمانات متانة قوية دون بناء تنسيق مخصص.

RTO وRPO للتحويل عند الإخفاق في الممارسة

مقياسان يحكمان ما تعِد به معمارية التوفر العالي للأعمال فعلياً:

  • هدف وقت الاسترداد (RTO): مدة عدم إتاحة قاعدة البيانات أثناء التحويل. مع Patroni، يكتمل التحويل التلقائي النموذجي في 15–45 ثانية من لحظة توقف الأساسي عن إرسال نبضات القلب (إعداد ttl في Patroni هو العامل المهيمن). تحقق الخدمات المُدارة مثل RDS Multi-AZ عادةً 20–60 ثانية. صمّم منطق إعادة المحاولة في اتصال تطبيقك حول هذه النافزة — قواطع الدائرة وإعادة المحاولة مع التراجع ليست اختيارية.
  • هدف نقطة الاسترداد (RPO): كمية البيانات التي يمكن فقدانها في أسوأ الحالات. مع التكرار غير المتزامن، يساوي RPO تأخر التكرار وقت الإخفاق — يحتمل أن تكون ثواني إلى دقائق من المعاملات المُنفَّذة. مع التكرار المتزامن على نسخة متماثلة واحدة على الأقل، يكون RPO صفراً للتحويل إلى تلك النسخة المتماثلة.
ممارسة احترافية — اختبر التحويل بانتظام: وثّق أهداف RTO/RPO، ثم قسها مقابل الواقع بحقن إخفاق أساسي مُتحكَّم به في بيئة التدريج (أو، مع ضوابط نطاق انفجار مناسبة، في الإنتاج خلال نافزة حركة مرور منخفضة). الفرق التي لم تختبر التحويل قط تكتشف أثناء حادثة فعلية أن تطبيقها لا يُعيد الاتصال بنظافة، أو أن مجمّع الاتصالات يحتفظ باتصالات قديمة، أو أن نظام المراقبة يُطلق 20 تنبيهاً في وقت واحد دون دليل تشغيل واضح. اجعل اختبار التحويل طقساً ربع سنوي.

التوفر العالي متعدد مناطق التوفر مقابل متعدد المناطق

التكرار المتزامن عبر مناطق التوفر (AZs داخل نفس منطقة AWS) هو الأساس في الإنتاج — رحلة الشبكة 0.5–2 مللي ثانية، مما يجعل التنفيذ المتزامن عملياً. التكرار المتزامن عبر مناطق (زمن استجابة 50–200 مللي ثانية) نادراً ما يُستخدم لـ OLTP لأن عقوبة زمن استجابة الكتابة حظرية. النسخ المتماثلة عبر المناطق تكون دائماً تقريباً غير متزامنة وتُستخدم كأهداف استرداد الكوارث (DR)، لا مرشحات للتحويل التلقائي. المقايضة: إذا فُقدت المنطقة الأساسية بالكامل، فإن ترقية نسخة متماثلة غير متزامنة عبر المناطق هي عملية يدوية وتقبل فقدان البيانات المساوي لتأخر التكرار.

تحل قاعدة بيانات AWS Aurora العالمية جزءاً من هذا باستخدام طبقة التخزين المخصصة للتكرار عبر المناطق بأقل من ثانية واحدة من التأخر — لا تزال غير متزامنة بمعنى CAP، لكن تشغيلياً أسرع بكثير من التكرار التدفقي التقليدي. للأنظمة التي تتطلب RPO صفري عبر المناطق، تكون Spanner أو CockroachDB مع التوافق المتزامن متعدد المناطق هي الخيارات، بتكلفة وتعقيد كبيرين.