اتساق البيانات والنسخ

نماذج الاتساق

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

نماذج الاتساق

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

يتناول هذا الدرس النماذج الأربعة التي ستقابلها في كل نقاش جدي حول تصميم الأنظمة: الاتساق القوي، والاتساق النهائي، والاتساق السببي، واتساق قراءة ما كتبته. سنتناول ما يضمنه كل نموذج، وما تكلفته، وأين يظهر في الأنظمة الحقيقية التي تستخدمها.

فكرة محورية: نماذج الاتساق طيف متدرج، وليست خياراً ثنائياً. السؤال ليس "متسق أم لا؟" — بل دائماً: "ما الضمانات التي يحتاجها مستخدمو نظامي فعلاً، وما الذي أرغب في دفعه من كمون وتوفر لتحقيقها؟"

الاتساق القوي (الخطية)

يكون النظام متسقاً بصورة قوية — وبدقة أكبر: خطياً — حين تُعيد كل عملية قراءة أحدث كتابة مُؤكدة، وتبدو جميع العمليات كأنها تحدث آنياً عند نقطة واحدة في الزمن الكوني. من الخارج، يتصرف النظام الموزع كأنه عقدة واحدة تحوي نسخة واحدة من البيانات.

الضمان الملموس: إذا كتب العميل A القيمة x = 5 وتأكدت عملية الكتابة، فإن أي قراءة لاحقة من أي عميل في أي مكان في الكتلة ستُعيد 5، وليس أي قيمة أقدم.

أمثلة من الواقع:

  • Google Spanner (TrueTime) — SQL عالمي بتناسق خارجي
  • etcd وZooKeeper — تُستخدم تحديداً لتنسيق الكتل بسبب كتاباتها الخطية
  • قواعد البيانات أحادية العقدة (PostgreSQL على خادم واحد) — خطية بالتعريف

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

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

الاتساق النهائي

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

الضمان الملموس: إذا كتب العميل A القيمة x = 5 ثم قرأ العميل B فوراً من نسخة متماثلة مختلفة، فقد يرى B القيمة القديمة x = 3. بعد اكتمال الانتشار — عادةً ميلي ثانية من الناحية العملية، لكنها غير محدودة نظرياً — ستُعيد كل نسخة 5.

أمثلة من الواقع:

  • Amazon DynamoDB (الافتراضي) — تُؤكَّد الكتابة بعد منطقة واحدة مع انتشار غير متزامن
  • Apache Cassandra (مستوى تناسق ONE) — قابل للضبط، لكن الافتراضي هو النهائي
  • DNS — قد لا يكون تحديث سجل TXT مرئياً في كل مكان لمدة 48 ساعة
  • أعداد "الإعجابات" في الشبكات الاجتماعية — رؤية 1,421 بدلاً من 1,423 لثوانٍ أمر مقبول

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

Strong vs Eventual Consistency — Timeline Comparison Strong Consistency Client A Primary x=3 → x=5 Replica syncs before ACK write x=5 sync ACK (both confirmed) Client B read x returns x=5 ✓ Eventual Consistency Client A Primary x=3 → x=5 Replica still x=3 (lag) write x=5 async ACK (primary only) Client B read x (replica) returns x=3 (stale!) After propagation (ms-seconds) Replica converges → x=5 ✓ Higher latency, always correct Lower latency, temporarily stale
الاتساق القوي يتطلب تأكيداً من جميع النسخ قبل الإيصال؛ الاتساق النهائي يُصدر الإيصال فوراً وينتشر بشكل غير متزامن.

الاتساق السببي

الاتساق السببي هو منطقة وسطى تحافظ على علاقة السبب والأثر بين العمليات. إذا كانت العملية B تعتمد سببياً على العملية A (مثلاً: رد يعتمد على منشور)، فإن كل عميل يرى B يجب أن يكون قد رأى A أولاً. أما العمليات التي لا ترتبط سببياً فيمكن رؤيتها بأي ترتيب.

لماذا يهم — مثال التعليقات: تخيّل منصة اجتماعية. نشر المستخدم A: "استقلت اليوم." فرد المستخدم B: "تهاني!" إذا وصل رد B إلى المستخدم C دون أن يصل منشور A الأصلي أولاً، سيكون C محتاراً. الاتساق السببي يمنع هذا: لن يصل الرد أبداً قبل المنشور الذي يرد عليه.

كيف يُطبَّق: تتتبع قواعد البيانات التبعيات السببية باستخدام ساعات المتجهات أو متجهات الإصدار. تحمل كل كتابة رمزاً وصفياً. عندما تستقبل عقدة ما طلب قراءة أو كتابة، تتحقق من أن جميع الكتابات السابقة سببياً قد طُبِّقت بالفعل قبل تلبية الطلب.

أمثلة من الواقع:

  • جلسات MongoDB السببية المتسقة — مُدخلة في الإصدار 4.0، تضمن اتساق قراءة ما كتبته داخل الجلسة
  • كتابات DynamoDB المشروطة مع فحوصات الإصدار
  • أنظمة التحرير التعاوني (Google Docs يستخدم متغيراً للتحويلات التشغيلية)

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

اتساق قراءة ما كتبته

قراءة ما كتبته (يُسمى أيضاً قراءة كتاباتك الخاصة) ضمان مقيّد بالجلسة: بعد أن يكتب العميل قيمة، سيقرأ دائماً على الأقل تلك النسخة — وليس أي قيمة أقدم. قد يرى العملاء الآخرون بيانات قديمة.

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

استراتيجيات التطبيق الملموسة:

  • جلسات ثابتة: توجيه جميع طلبات نفس العميل إلى نفس النسخة المتماثلة. بسيط، لكنه يخلق نقاطاً ساخنة ويفشل إذا تعطلت تلك النسخة.
  • القراءة من الأساسي بعد الكتابة: لنافذة زمنية قابلة للضبط (مثلاً 60 ثانية بعد آخر كتابة)، يُوجَّه قراءات ذلك المستخدم إلى الأساسي. بعد انتهاء النافذة، تستأنف القراءات من النسخة المتماثلة.
  • نشر طابع زمني للكتابة: تُعيد الكتابة رمزاً للنسخ (طابع زمني أو LSN). يُمرر العميل هذا الرمز في القراءات اللاحقة؛ أي نسخة لم تطبق بعد تلك الكتابة تُتخطى.

أمثلة من الواقع:

  • جدول الإطار الزمني في تويتر — تظهر تغريداتك فوراً في جدولك (قراءة ما كتبته)، لكن التغذية العالمية قد تتأخر قليلاً
  • قراءات DynamoDB القوية الاتساق عند الطلب — علامة لكل طلب تدفع RCUs إضافية لضمان قراءة ما كتبته
  • PostgreSQL مع synchronous_commit = local وتوجيه على مستوى التطبيق
Four Consistency Models — Spectrum and Properties Weaker guarantees Stronger guarantees Eventual No ordering guarantees Highest availability Lowest latency Read-Your-Writes Session scoped writer sees own writes High availability Low latency Causal Cause before effect Vector clocks Med availability Med latency Strong (Linear) Single-copy illusion Global order Lower availability Higher latency DNS, likes, view counts Profile edits, feed posts Comments, chat threads Bank transfers, inventory locks
طيف الاتساق — من النهائي (أعلى توفر، أدنى كمون) إلى القوي/الخطي (أدنى توفر، أعلى كمون).

اختيار النموذج الصحيح

تُقطع الأسئلة التالية معظم حالات الغموض في القرار:

  1. هل يمكن للمستخدمين تحمل قراءة بيانات قديمة؟ عداد "إعجاب" يختلف بمقدار 5 لثانية: نعم. رصيد بنكي يختلف بـ 200 دولار: بالتأكيد لا.
  2. هل العمليات مترابطة سببياً؟ نقاش متشعب، مستند تعاوني، أو سير عمل تنفيذ طلب — كلها تبعيات سببية قوية. استخدم الاتساق السببي أو أقوى.
  3. هل الكتابة نهاية التفاعل أم بداية جلسة؟ إذا رأى المستخدمون فوراً ما كتبوه للتو (تحديثات الملف الشخصي، تغييرات الإعدادات)، فأنت بحاجة على الأقل لاتساق قراءة ما كتبته.
  4. ما متطلبات التوزيع الجغرافي؟ إذا امتد النظام عبر قارات ويجب أن يخدم قراءات أقل من 50 مللي ثانية عالمياً، فالاتساق القوي غير عملي. الاتساق النهائي أو السببي مع التوجيه الذكي هو المسار الوحيد القابل للتطبيق.
أفضل الممارسات: تستخدم كثير من الأنظمة الإنتاجية نماذج اتساق مختلفة لأجزاء مختلفة من التطبيق ذاته. تستخدم Stripe الاتساق القوي لسجلات الدفع والاتساق النهائي لعدادات التحليلات. الاختيار حسب حالة الاستخدام بدلاً من نموذج واحد للنظام كله هو القرار الصحيح في الغالب.

يُعدّ الفهم العميق لهذه النماذج الأربعة — ما يضمنه كل منها، وما تكلفته، وأين ينهار — أساس كل درس في هذه الدورة. سنستحضر هذه المفردات باستمرار حين نستكشف استراتيجيات النسخ المتماثل وخوارزميات التوافق والمعاملات الموزعة.