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

المعاملات الموزعة وبروتوكول الإتمام على مرحلتين

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

المعاملات الموزعة وبروتوكول الإتمام على مرحلتين

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

لماذا لا يكفي ACID المحلي

داخل قاعدة بيانات واحدة، تمنحك المحرّك ACID مجاناً: أمر BEGIN … COMMIT إما يُطبّق جميع الكتابات أو يتراجع عنها كلياً. أما عبر الخدمات، فلا يوجد سجل معاملات مشترك. كل خدمة لا ترى إلا مخزنها الخاص. ويتطلب التنسيق بينها بروتوكولاً يثق به كلا الطرفين حتى عند فشل الشبكة في منتصف الطريق.

بروتوكول الإتمام على مرحلتين (2PC)

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

  1. المرحلة الأولى — الإعداد (التصويت): يُرسل المنسّق طلب PREPARE إلى كل مشارك. يكتب كل مشارك التغييرات المقصودة في سجل كتابة مسبقة (WAL) مستدام، ويُقفل الصفوف المعنية، ويردّ بـYES (مستعد للإتمام) أو NO (إلغاء).
  2. المرحلة الثانية — الإتمام أو الإلغاء: إذا صوّت جميع المشاركين بـYES، يُسجّل المنسّق COMMIT ويُرسله للجميع. إذا صوّت أي مشارك بـNO أو انتهت المهلة، يُسجّل المنسّق ABORT ويُرسل ROLLBACK. يُطبّق المشاركون التغييرات أو يتراجعون عنها ويُحرّرون الأقفال.
Two-Phase Commit sequence diagram Client Coordinator Participant A & B PHASE 1 — PREPARE BEGIN TRANSACTION PREPARE (lock rows, write WAL) VOTE: YES PHASE 2 — COMMIT Log COMMIT to disk COMMIT ACK (locks released) COMMIT OK ABORT PATH — if any participant votes NO ROLLBACK (undo WAL, release locks) TRANSACTION ABORTED
بروتوكول 2PC: المرحلة الأولى تجمع الأصوات؛ المرحلة الثانية تُتمّ فقط إذا صوّت الجميع بنعم، وإلا تتراجع.

مشكلة التعليق (Blocking Problem)

بروتوكول 2PC هو بروتوكول تعليقي. تخيّل سيناريو: ينهار المنسّق مباشرةً بعد تسجيل COMMIT على القرص ولكن قبل إرسال رسالة COMMIT إلى المشاركين. المشاركون عالقون: لقد أقفلوا صفوفهم ولا يستطيعون اتخاذ قرار بمفردهم. يجب أن ينتظروا حتى يتعافى المنسّق. وطوال تلك الفترة، تلك الصفوف غير متاحة — وقد يستمر ذلك دقائق أو أطول.

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

الاستخدام الفعلي: معاملات XA

معيار XA (الصادر عن The Open Group) هو التطبيق الأكثر شيوعاً لـ2PC. تدعمه MySQL وPostgreSQL وOracle وIBM MQ. تستخدمه تطبيقات Java عبر javax.transaction.XAResource. دور المنسّق تؤديه عادةً أداة إدارة معاملات مثل Atomikos أو Narayana أو أي خادم تطبيقات يدعم JTA.

مثال في سياق الخدمات المصغّرة المصرفية: تعمل خدمة الدفع منسّقاً؛ تفتح معاملة XA تشمل قاعدة بيانات الحسابات (PostgreSQL) وقاعدة بيانات دفتر الأستاذ (MySQL). تُجري قاعدتا البيانات مرحلة الإعداد، يُتمّ المنسّق الإتمام، وتُطبّق كلتاهما التغييرات. من منظور المستخدم، يظهر الخصم والإيداع في وقت واحد.

خصائص الأداء

تُضيف جولة 2PC واحدة ما لا يقل عن 2 × زمن الرحلة الذهابية والإيابية للشبكة + 2 × مزامنة القرص إلى كل معاملة. عند 5 مللي ثانية RTT و1 مللي ثانية fsync، يصل ذلك إلى نحو 12 مللي ثانية من الحمل الزائد قبل تشغيل أي منطق تطبيقي. في الأنظمة ذات الإنتاجية العالية (آلاف المعاملات في الثانية)، يتراكم هذا بسرعة. والأقفال الممسوكة عبر الشبكة تُقلّل التزامن بشكل أكبر. هذه التكاليف تفسّر لماذا تُفضّل معماريات الخدمات المصغّرة الحديثة أنماط الاتساق النهائي (Sagas والـOutbox) على 2PC في العمليات طويلة الأمد أو العابرة للخدمات.

2PC مناسب لـ: المعاملات القصيرة منخفضة الكمون عبر عدد صغير من المشاركين (2-3 قواعد بيانات في مركز بيانات واحد)، حيث الذرية الصارمة ضرورة لا تقبل المساومة — مثل القيد المزدوج في المحاسبة المالية أو حجز المخزون في مستودع. وهو غير مناسب للعمليات متعددة الخدمات عبر الإنترنت العام أو للعمليات التي تستغرق أكثر من بضع مئات من المللي ثانية.

بروتوكول الإتمام على ثلاث مراحل (3PC) — ملاحظة موجزة

يحاول بروتوكول 3PC حل مشكلة التعليق بإدراج مرحلة ما قبل الإتمام بين الإعداد والإتمام. لكنه يُدخل وضع فشل جديداً في حالة انقسام الشبكة (إتمام في جزء مقابل إلغاء في جزء آخر)، ونادراً ما يُستخدم عملياً. تبقى معظم الأنظمة مع 2PC وتستثمر في منسّقين عالي التوافر بدلاً من تعقيدات 3PC.

البدائل ومتى تستخدمها

بسبب تكاليف التعليق والأداء في 2PC، تقاربت الصناعة على هذه البدائل لمعظم سيناريوهات الخدمات المصغّرة:

  • نمط Outbox مع CDC: اكتب الحدث في جدول outbox ضمن المعاملة المحلية نفسها مع بيانات العمل. تتولى عملية Change-Data-Capture (مثل Debezium) تتبع WAL ونشر الحدث. ذري داخل قاعدة بيانات واحدة؛ اتساق نهائي عبر الخدمات.
  • Sagas (تنسيق أو تنظيم): تقسيم المعاملة الموزعة إلى سلسلة من المعاملات المحلية، كل منها ينشر حدثاً. المعاملات التعويضية تتولى التراجع. مُغطّى في الدرس التاسع.
  • Google Spanner / CockroachDB: قواعد بيانات موزعة تُطبّق بروتوكول إتمام موزع داخلياً، تُخفي التعقيد عن التطبيق وتحقق عزلاً قابلاً للتسلسل على نطاق عالمي.
قاعدة القرار: استخدم 2PC عندما تتحكم في جميع المشاركين وهم في موضع مشترك (مركز بيانات واحد، زمن رحلة أقل من ملي ثانية)، وتحتاج إلى الذرية ويمكنك تحمّل خطر التعليق، والمعاملة قصيرة الأمد (أقل من 100 مللي ثانية). وإلا فالجأ إلى Sagas أو نمط Outbox.
2PC vs Saga trade-off comparison Two-Phase Commit (2PC) Strengths + Atomic across all participants + No compensating logic needed + ACID semantics preserved Weaknesses - Blocking on coordinator failure - Locks held across network - High latency overhead - Not suitable for long transactions Saga Pattern Strengths + No blocking / no locks held + Works across the internet + Scales to many participants Weaknesses - Compensating txns add complexity - Eventual consistency only - Harder to reason about correctness - Partial failures visible to users
مقارنة 2PC مقابل Saga: الاختيار يعتمد على متطلبات الكمون وبنية المشاركين ومدى تحمّل الرؤية الجزئية للفشل.

النقاط الرئيسية

  • يُنسّق 2PC إتماماً ذرياً عبر مشاركين مستقلين متعددين باستخدام بروتوكول إعداد → إتمام/إلغاء.
  • المنسّق نقطة فشل واحدة؛ يجب أن يكون سجله مستداماً حتى يُعيد إرسال قراراته بعد الانهيار.
  • يمسك المشاركون الأقفال بين المرحلة الأولى والثانية، مما يخلق نافذة تعليق تتناسب مع وقت تعافي المنسّق.
  • XA هو التطبيق القياسي، وهو مدعوم في قواعد البيانات العلاقية والبرمجيات الوسيطة للمؤسسات.
  • في معظم معماريات الخدمات المصغّرة الحديثة، يُفضّل نمط Outbox وSagas — يُقايضان الذرية الصارمة بالتوافر وقابلية التوسع.