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

عندما تُوزع قاعدة بيانات عبر عدة آلات (نسخ)، تحصل على سرعة ومتانة—لكنك تُدخل أيضًا فترات حيث تلك الآلات لا تتفق تمامًا أو لا تتواصل بشكل موثوق.
الاتساق يعني: بعد كتابة ناجحة، كل القراءات تُرجع نفس القيمة. إذا حدّثت بريدك الإلكتروني في الملف الشخصي، فالقراءة التالية—بغض النظر عن النسخة التي ترد—تعيد البريد الجديد.
عمليًا، الأنظمة التي تُعطي أولوية للاتساق قد تؤخر أو ترفض بعض الطلبات أثناء الأعطال لتجنب إرجاع إجابات متضاربة.
التوافر يعني: النظام يرد على كل طلب، حتى لو كانت بعض الخوادم متوقفة أو منفصلة. قد لا تحصل على أحدث البيانات، لكنك تحصل على إجابة.
عمليًا، الأنظمة التي تفضل التوافر قد تقبل الكتابات وتخدم القراءات حتى بينما تختلف النسخ، ثم تُصالح الاختلافات لاحقًا.
المقايضة تعني أنك لا تستطيع تعظيم الهدفين في نفس الوقت في كل سيناريو فشل. إذا لم تستطع النسخ التنسيق، يجب على قاعدة البيانات إما:
التوازن الصحيح يعتمد على الأخطاء التي يمكنك تحملها: انقطاع قصير، أم فترة قصيرة من البيانات الخاطئة/القديمة. معظم الأنظمة الحقيقية تختار نقطة وسط—وتجعل المقايضة صريحة.
تُسمى قاعدة البيانات "موزعة" عندما تخزن وتخدم البيانات من عدة آلات (عقد) تتنسيق عبر الشبكة. للتطبيق، قد تبدو كقاعدة بيانات واحدة—لكن داخليًا، قد تُخدم الطلبات بواسطة عقد مختلفة في أماكن مختلفة.
معظم قواعد البيانات الموزعة تُكرر البيانات: نفس السجل مخزن على عقد متعددة. تفعل الفرق ذلك لـ:
التكرار قوي، لكنه يطرح فورًا سؤالًا: إذا كان لدى عقدتين نسخة من نفس البيانات، كيف تضمن أنهما دائمًا متفقتان؟
على خادم واحد، "متوقف" واضح: الآلة تعمل أم لا. في نظام موزع، الفشل غالبًا ما يكون جزئيًا. قد تكون عقدة حية لكنها بطيئة. قد يسقط رابط الشبكة حزمًا. قد يفقد رف كامل الاتصال بينما يستمر باقي العنقود بالعمل.
هذا مهم لأن العقد لا يمكنها أن تعرف فورًا ما إذا كانت العقدة الأخرى متوقفة فعليًا، أو لا يمكن الوصول إليها مؤقتًا، أو مجرد متأخرة. أثناء انتظارهم لمعرفة ذلك، عليهم أن يقرروا ماذا يفعلون مع القراءات والكتابات الواردة.
مع خادم واحد، هناك مصدر واحد للحقيقة: كل قراءة ترى آخر كتابة ناجحة.
مع عدة عقد، "الأحدث" يعتمد على التنسيق. إذا نجحت كتابة على العقدة A لكن العقدة B لا يمكن الوصول إليها، هل على قاعدة البيانات أن:
التوتر هذا—الذي تجلبه الشبكات غير الكاملة—هو سبب تغير القواعد.
انقسام الشبكة هو كسر في الاتصال بين عقد يفترض أن تعمل كقاعدة بيانات واحدة. قد تظل العقد تعمل وصحية، لكنها لا تستطيع تبادل الرسائل بثقة—بسبب سويتش معطل، رابط مثقل، تغيير توجيه خاطئ، قاعدة جدار ناري خاطئة، أو حتى جار صاخب في شبكة سحابية.
بمجرد أن ينتشر النظام عبر آلات متعددة (غالبًا عبر رفوف، مناطق، أو مناطق إقليمية)، لم تعد تتحكم في كل قفزة بينهما. الشبكات تفقد حزمًا، تُدخل تأخيرات، وأحيانًا تتقسم إلى "جزر". على نطاق صغير تكون هذه الأحداث نادرة؛ على نطاق كبير تصبح روتينية. حتى اضطراب قصير يكفي لأن يؤثر، لأن قواعد البيانات تحتاج تنسيقًا مستمرًا للاتفاق على ما حدث.
أثناء الانقسام، يستمر كلا الجانبين في تلقي الطلبات. إذا سمح للمستخدمين بالكتابة على كلا الجانبين، قد يقبل كل جانب تحديثات لا يراها الآخر.
مثال: العقدة A تحدّث عنوان المستخدم إلى "الشارع الجديد". في نفس الوقت، العقدة B تحدّثه إلى "الشارع القديم شقة 2". كل جانب يعتقد أن كتابته هي الأحدث—لأنه لا يستطيع المقارنة في الوقت الحقيقي.
الانقسامات لا تظهر كرسائل خطأ مرتبة؛ تظهر كسلوك محير:
هذه هي نقطة الضغط التي تُجبر الاختيار: عندما لا تضمن الشبكة الاتصال، يجب على قاعدة البيانات الموزعة أن تختار بين إعطاء الأولوية للاتساق أو للتوافر.
CAP هي طريقة موجزة لوصف ما يحدث عندما تُوزع قاعدة البيانات عبر عدة آلات.
عندما لا يوجد انقسام، كثير من الأنظمة يمكن أن تبدو متسقة ومُتاحة.
عندما يوجد انقسام، عليك اختيار ما تُعطيه الأولوية:
balance = 100 إلى الخادم A.balance = 80.CAP لا يعني "اختر اثنين" كقاعدة دائمة. يعني أثناء الانقسام لا يمكنك ضمان كلا:
في الخارج عن الانقسامات، يمكنك غالبًا الاقتراب من كلتيهما—حتى تخطئ الشبكة.
اختيار الاتساق يعني أن قاعدة البيانات تُعطي أولوية لأن "الجميع يرى نفس الحقيقة" بدلًا من "الاستجابة دائمًا". عمليًا، هذا يشير غالبًا إلى الاتساق القوي، وغالبًا ما يُوصف بأنه سلوك قابل للتسلسل الخطي (linearizable): بمجرد أن تُعترف بكتابة، أي قراءة لاحقة (من أي مكان) تُرجع تلك القيمة، كما لو كان هناك نسخة واحدة حديثة.
عندما تنقسم الشبكة ولا تستطيع النسخ التنسيق بأمان، لا يمكن لنظام متسق بقوة أن يقبل تحديثات مستقلة على كلا الجانبين. لحماية الصحة، عادةً ما:
من منظور المستخدم، قد يبدو هذا كتعطل رغم أن بعض الآلات لا تزال تعمل.
الفائدة الرئيسية هي تبسيط التفكير. يمكن لكود التطبيق أن يتصرف كما لو أنه يتعامل مع قاعدة بيانات واحدة، لا عدة نسخ قد تختلف. هذا يقلل من "اللحظات الغريبة" مثل:
كما تحصل على نماذج عقلية أنظف للتدقيق والفوترة وكل ما يجب أن يكون صحيحًا من المرة الأولى.
للتمسك بالاتساق تكلفة حقيقية:
إذا كان منتجك لا يتحمل طلبات فاشلة أثناء انقطاعات جزئية، قد يبدو الاتساق القوي مكلفًا—حتى لو كان الخيار الصحيح للصحة.
اختيار التوافر يعني أنك تُحسّن من وعد بسيط: النظام يرد، حتى عندما تكون أجزاء البنية التحتية غير صحية. عمليًا، "التوفر العالي" ليس "لا أخطاء أبدًا"—بل أن معظم الطلبات لا تزال تتلقى إجابة أثناء فشل العقد، التحميل الزائد، أو روابط الشبكة المعطوبة.
عندما تنقسم الشبكة، لا تستطيع النسخ التواصل بثقة. قاعدة بيانات تفضل التوافر عادةً تستمر في خدمة الحركة من الجانب الذي يمكن الوصول إليه:
هذا يُبقي التطبيقات تتحرك، لكنه يعني أيضًا أن نسخًا مختلفة قد تقبل حقائق مختلفة مؤقتًا.
تحصل على توفر أفضل: المستخدمون ما زالوا يتصفحون، يضعون عناصر في العربة، ينشرون تعليقاتًا، أو يسجلون أحداثًا حتى لو عزلت منطقة.
تحصل أيضًا على تجربة مستخدم أنعم تحت الضغط. بدلًا من انتهاء المهلات، يمكن لتطبيقك أن يستمر بسلوك معقول ("تم حفظ التحديث") ثم يُزامن لاحقًا. لعدة أحمال استهلاكية وتحليلية، تستحق هذه المقايضة.
الثمن هو أن قاعدة البيانات قد تُرجع قراءات قديمة. قد يحدث أن يحدث مستخدم تحديثًا على نسخة ثم يقرأ فورًا من نسخة أخرى فيرى القيمة القديمة.
كما أنك تُعرِّض نفسك لخطر نزاعات الكتابة. قد يقبل مستخدمان تحديثات متضاربة على جانبي الانقسام. عند شفاء الانقسام، يجب على النظام مصالحة التواريخ المتباينة: حسب القواعد قد "يفوز" أحدهما، أو تُدمج الحقول، أو تتطلب المصالحة منطق التطبيق.
تصميم بنية تفضّل التوافر يعني قبول الخلافات مؤقتًا حتى يظل المنتج مستجيبًا—ثم الاستثمار في اكتشاف وإصلاح الخلاف لاحقًا.
الحشود هي تقنية تصويت عملية تستخدمها كثير من قواعد البيانات المكررة لموازنة الاتساق والتوافر. بدلاً من الوثوق بنسخة واحدة، يطلب النظام من عدد كافٍ من النسخ الموافقة.
سترى غالبًا الحشود موصوفة بثلاثة أرقام:
قاعدة إبهام شائعة: إذا كانت R + W > N، فكل قراءة تتقاطع مع كتابة ناجحة على الأقل في نسخة واحدة، مما يقلل احتمال قراءة بيانات قديمة.
لو كان لديك N=3 نسخ:
بعض الأنظمة تذهب أبعد وتضع W=3 (كل النسخ) لاتساق أقوى، لكن ذلك قد يسبب مزيدًا من فشل الكتابة عندما تكون أي نسخة بطيئة أو معطلة.
الحشود لا تقضي على مشاكل الانقسام—بل تعرّف من المسموح له بالتقدم. إذا انقسمت الشبكة 2–1، الجانب الذي يملك 2 نسخ ما زال يستطيع تلبية R=2 وW=2، بينما النسخة المعزولة الفردية لا تستطيع. هذا يقلل من التحديثات المتعارضة، لكنه يعني أن بعض العملاء سيواجهون أخطاء أو انتهاء مهلات.
الحشود عادةً تعني كمون أعلى (مزيد من العقد للتواصل)، تكلفة أعلى (حركة بين العقد)، وسلوك فشل أكثر دقة (انتهاء المهلة قد يبدو كعدم توفر). الفائدة أنها أرضية وسطى قابلة للضبط: يمكنك تغيير R وW لتقريب القراءات من الأحدث أو لرفع نجاح الكتابة حسب الأهمية.
الاتساق النهائي يعني أن النسخ مسموح لها أن تكون غير متزامنة مؤقتًا، طالما أنها تتقارب لنفس القيمة لاحقًا.
تخيل سلسلة مقاهي تحدث لافتة "نفد المنتج" لكعكة مشتركة. متجر واحد يعلّمها "نفدت"، لكن التحديث يصل للمتاجر الأخرى بعد دقائق. خلال تلك النافذة، قد يظل متجر آخر يعرض "متاحة" ويبيع القطعة الأخيرة. النظام ليس "معطّلاً"—التحديثات فقط تتأخر في الوصول.
بينما تنتشر البيانات، قد يلاحظ العملاء سلوكًا مفاجئًا مثل:
أنظمة الاتساق النهائي تضيف آليات خلفية لتقليل نوافذ عدم التناسق:
يناسب عندما يكون التوفر أهم من الحداثة التامة: خلاصات النشاط، عدادات المشاهدات، التوصيات، الملفات المؤقتة، السجلات/التليمتري، وبيانات أخرى غير حاسمة حيث أن "تصحيحها بعد لحظة" مقبول.
عندما تقبل قاعدة بيانات كتابات على نسخ متعددة، قد ينتهي بها الأمر بنزاعات: تحديثان (أو أكثر) لنفس العنصر حدثا بشكل مستقل على نسخ مختلفة قبل مزامنتها.
مثال كلاسيكي: مستخدم يحدّث عنوان الشحن على جهاز، وفي الوقت نفسه يغيّر رقم هاتفه على جهاز آخر. إذا هبط كل تحديث على نسخة مختلفة أثناء فصل مؤقت، يجب على النظام أن يقرر ما هو السجل "الحقيقي" عندما تتبادل النسخ البيانات مرة أخرى.
تبدأ كثير من الأنظمة بـآخر كتابة تفوز: التحديث ذو الطابع الزمني الأحدث يطغى على البقية.
جاذبيته أنه سهل التنفيذ وسريع الحساب. العيب أنه يمكن أن يفقد البيانات بصمت. إذا "الأحدث" يفوز، قد يُلغى تحديث أقدم لكنه مهم—حتى لو لمس الحقول مختلفة.
كما يفترض أن الساعات موثوقة. انحراف الساعة بين الآلات (أو العملاء) قد يجعل التحديث «الخطأ» يفوز.
التعامل الأكثر أمانًا يتطلب عادة تتبع التاريخ السببي.
مفاهيميًا، تُلحق متجهات الإصدارات (وأشباهها الأبسط) قطعة بيانات صغيرة بكل سجل تلخص "أية نسخة رأت أية تحديثات". عندما تتبادل النسخ النسخ، يمكن لقاعدة البيانات اكتشاف ما إذا كانت نسخة واحدة تشمل الأخرى (لا تعارض) أو أنها تفرعت (تعارض يحتاج حل).
تستخدم بعض الأنظمة طوابعًا منطقية (مثل ساعات لامبورت) أو ساعات هجينة منطقية لتقليل الاعتماد على وقت الحائط وفي نفس الوقت إعطاء تلميح لترتيب الأحداث.
عند اكتشاف تعارض، لديك خيارات:
النهج الأفضل يعتمد على ما يعنيه "الصحيح" لبياناتك—أحيانًا فقدان كتابة مقبول، وأحيانًا يكون خطأً حرجًا للأعمال.
اختيار وضع الاتساق/التوافر ليس نقاشًا فلسفيًا—إنه قرار منتج. ابدأ بالسؤال: ما تكلفة الخطأ للحظة، وما تكلفة إظهار "حاول لاحقًا"؟
بعض المجالات تحتاج إجابة موحدة فورًا لأن "شبه صحيح" لا يكفي:
إذا كان أثر عدم التناسق مؤقتًا منخفضًا أو قابلًا للتراجع، يمكنك الميل أكثر للتوافر.
العديد من تجارب المستخدم تعمل جيدًا مع قراءات متأخرة قليلًا:
كن صريحًا بشأن كم من التأخير مقبول: ثوانٍ، دقائق، أم ساعات. تلك الميزانية الزمنية توجه اختياراتك في التكرار والحشود.
عندما لا تستطيع النسخ الاتفاق، عادةً تواجه أحد ثلاثة نتائج في تجربة المستخدم:
اختر الخيار الأقل ضررًا لكل ميزة، لا بشكل عام.
امِل للاتساق إذا: نتائج خاطئة تُسبب خطرًا ماليًا/قانونيًا، مسائل أمنية، أو إجراءات لا رجعة فيها.
امِل للتوافر إذا: المستخدمون يقدّرون الاستجابة، والبيانات القديمة مقبولة، ويمكن حل التعارضات بأمان لاحقًا.
عند الشك، قسّم النظام: احتفظ بالسجلات الحيوية متسقة بقوة، ودع العروض المشتقة (الخلاصات، الكاش، التحليلات) تميل نحو التوافر.
نادراً ما تضطر لاختيار إعداد اتساق واحد للنظام كله. كثير من قواعد البيانات الموزعة الحديثة تتيح اختيار الاتساق لكل عملية—والتطبيقات الذكية تستفيد من ذلك للحفاظ على تجربة مستخدم سلسة دون تجاهل المقايضة.
عامل الاتساق كقرص يتم تضييقه حسب ما يفعله المستخدم:
هذا يجنب دفع تكلفة الاتساق الأقصى على كل شيء بينما يحمي العمليات المهمة.
نمط شائع هو قوي للكتابة، أضعف للقراءة:
في حالات أخرى، يعمل العكس: كتابات سريعة (مُؤجلة/نهائية) بالإضافة إلى قراءات قوية عند التأكيد ("هل تم تقديم طلبي؟").
عندما تتذبذب الشبكات، يعيد العملاء المحاولة. اجعل المحاولات آمنة بمفاتيح عدم التكرار حتى لا ينشأ أمران عند تنفيذ "إرسال الطلب" مرتين. خزّن وأعد استخدام النتيجة الأولى عند رؤية نفس المفتاح مرة أخرى.
للإجراءات متعددة الخطوات عبر خدمات، استخدم Saga: كل خطوة لها إجراء تعويضي مقابِل (استرداد، إرجاع حجز، إلغاء شحن). هذا يحافظ على إمكانية استرداد النظام حتى عندما تختلف أجزاء مؤقتًا أو تفشل.
لا يمكنك إدارة المقايضة إذا لم ترها. مشاكل الإنتاج غالبًا تبدو كـ"أخطاء عشوائية" حتى تضيف القياسات والاختبارات المناسبة.
ابدأ بمجموعة صغيرة من المقاييس التي ترتبط مباشرة بتأثير المستخدم:
إذا استطعت، صنّف المقاييس حسب وضع الاتساق (حشد مقابل محلي) والمنطقة/المنطقة الفرعية لرصد أين يتباين السلوك.
لا تنتظر الانقطاع الحقيقي. في بيئة الاختبار، نفذ تجارب فوضى تحاكي:
تحقق ليس فقط من "النظام يبقى شغّالًا"، بل ما الضمانات التي تبقى: هل القراءات تبقى طازجة، هل الكتابات تُحجب، هل العملاء يحصلون على أخطاء واضحة؟
أضف تنبيهات لـ:
وأخيرًا، اجعل الضمانات صريحة: وثق ما يَعِد به نظامك أثناء التشغيل الطبيعي وأثناء الانقسامات، ودرّب فرق المنتج والدعم على ماذا قد يراه المستخدمون وكيفية الرد.
إذا كنت تستكشف هذه المقايضات في منتج جديد، من المفيد التحقق من الفرضيات مبكرًا—خصوصًا حول أوضاع الفشل، سلوك الإعادة، وكيف تبدو "القديمة" في واجهة المستخدم.
نهج عملي هو بناء نموذج أصغر لمسار العمل (مسار الكتابة، مسار القراءة، الإعادة/قابلية التكرار، ومهمة المصالحة) قبل الالتزام بهندسة كاملة. مع أدوات مثل Koder.ai، يمكن للفرق إطلاق تطبيقات ويب وخوادم عبر واجهة دردشة، التكرار بسرعة على نماذج البيانات وواجهات برمجة التطبيقات، واختبار أنماط اتساق مختلفة (مثلاً كتابات صارمة + قراءات مسترخية) بدون تكلفة تطوير تقليدية. عندما يطابق النموذج السلوك المطلوب، يمكنك تصدير الشيفرة المصدرية وتطويرها للإنتاج.
في قاعدة بيانات مكررة، يعيش «نفس» البيانات على عدة آلات. هذا يعزز المتانة ويمكنه تقليل الكمون، لكنه يطرح مشاكل تنسيق: قد تكون العقد بطيئة، غير قابلة للوصول، أو مقطوعة بسبب الشبكة، لذا لا يمكنها دائمًا الاتفاق فورًا على آخر كتابة.
الاتساق يعني: بعد كتابة ناجحة، أي قراءة لاحقة تُرجع تلك القيمة نفسها—بغض النظر عن أي نسخة تُخدم. عمليًا، تُطبق الأنظمة ذلك عبر تأخير أو رفض قراءات/كتابات حتى تؤكد عدد كافٍ من النسخ (أو القائد) التحديث.
التوافر يعني أن النظام يُرجع استجابة غير خطأ لكل طلب، حتى لو كانت بعض العقد غير متاحة أو لا تتواصل. قد تكون الاستجابة قديمة أو جزئية أو مبنية على معرفة محلية، لكن النظام يتجنب حظر المستخدمين أثناء الأعطال.
انقسام الشبكة هو كسر في الاتصال بين عقد كان من المفترض أن تعمل كنظام واحد. قد تظل العقد تعمل صحياً، لكن الرسائل لا تعبر الانقسام بثقة، وهذا يُجبر قاعدة البيانات على الاختيار بين:
أثناء الانقسام، قد يقبل كل جانب تحديثات لا يستطيع مشاركتها فورًا. هذا يمكن أن يؤدي إلى:
هذه هي النتائج المرئية للمستخدم عندما تعجز النسخ عن التنسيق مؤقتًا.
لا يعني ذلك "اختر اثنين إلى الأبد". المعنى أن عند حدوث انقسام لا يمكنك ضمان كل من:
خارج الانقسامات، قد تبدو الأنظمة أنها توفر كلاهما معظم الوقت—إلى أن تخطئ الشبكة.
الحشد يعتمد على التصويت بين النسخ:
قاعدة شائعة: R + W > N لتقليل احتمال قراءة بيانات قديمة. الحشود لا تلغي الانقسامات؛ لكنها تحدد أي جانب مسموح له بالتقدم (مثلاً الجانب الذي يملك الأغلبية).
الاتساق في النهاية تسمح بأن تكون النسخ غير متزامنة مؤقتًا شريطة أن تتقارب لاحقًا. المشكلات الشائعة:
تُخفف الأنظمة ذلك بآليات مثل ، ، وعمليات الدورية.
النزاعات تظهر عندما تقبل نسخ مختلفة كتابات متضاربة على نفس العنصر أثناء الانقطاع. استراتيجيات الحل:
اختر الاستراتيجية بناءً على معنى "الصحيح" لبياناتك.
قرّر بناءً على مخاطرة الأعمال وما الذي يكرهه المستخدمون أكثر: نتيجة خاطئة للحظة، أم رسالة "حاول مرة أخرى لاحقًا"؟
نماذج عملية: مستويات اتساق لكل عملية، مفاتيح عدم التكرار (idempotency)، وSagas للتعويض في تدفقات طويلة.