المعاملات الموزعة وبروتوكول الإتمام على مرحلتين
المعاملات الموزعة وبروتوكول الإتمام على مرحلتين
المعاملة الموزعة هي عملية يجب أن تنجح أو تفشل بشكل ذري عبر خدمتين أو أكثر أو قاعدتَي بيانات مستقلتين. المثال الكلاسيكي: نظام دفع يجب أن (1) يخصم من حساب العميل، و(2) يُضيف المبلغ إلى حساب التاجر، و(3) يُحدّث سجل المخزون — وكل ذلك على قواعد بيانات منفصلة. إذا نجحت الخطوة الثانية وانهارت الخطوة الثالثة، تحرّكت الأموال لكن المخزون أصبح خاطئاً. وهذه بالضبط هي المشكلة التي تحلّها المعاملات الموزعة.
لماذا لا يكفي ACID المحلي
داخل قاعدة بيانات واحدة، تمنحك المحرّك ACID مجاناً: أمر BEGIN … COMMIT إما يُطبّق جميع الكتابات أو يتراجع عنها كلياً. أما عبر الخدمات، فلا يوجد سجل معاملات مشترك. كل خدمة لا ترى إلا مخزنها الخاص. ويتطلب التنسيق بينها بروتوكولاً يثق به كلا الطرفين حتى عند فشل الشبكة في منتصف الطريق.
بروتوكول الإتمام على مرحلتين (2PC)
بروتوكول الإتمام على مرحلتين (2PC) هو الحل الكلاسيكي. يُدخل منسّقاً محايداً (عادةً الخدمة التي تُطلق المعاملة) وواحداً أو أكثر من المشاركين (كل منهم يمتلك مورداً — قاعدة بيانات، قائمة انتظار، ذاكرة تخزين مؤقت). يعمل البروتوكول في مرحلتين:
- المرحلة الأولى — الإعداد (التصويت): يُرسل المنسّق طلب
PREPAREإلى كل مشارك. يكتب كل مشارك التغييرات المقصودة في سجل كتابة مسبقة (WAL) مستدام، ويُقفل الصفوف المعنية، ويردّ بـYES(مستعد للإتمام) أوNO(إلغاء). - المرحلة الثانية — الإتمام أو الإلغاء: إذا صوّت جميع المشاركين بـYES، يُسجّل المنسّق
COMMITويُرسله للجميع. إذا صوّت أي مشارك بـNO أو انتهت المهلة، يُسجّل المنسّقABORTويُرسلROLLBACK. يُطبّق المشاركون التغييرات أو يتراجعون عنها ويُحرّرون الأقفال.
مشكلة التعليق (Blocking Problem)
بروتوكول 2PC هو بروتوكول تعليقي. تخيّل سيناريو: ينهار المنسّق مباشرةً بعد تسجيل COMMIT على القرص ولكن قبل إرسال رسالة COMMIT إلى المشاركين. المشاركون عالقون: لقد أقفلوا صفوفهم ولا يستطيعون اتخاذ قرار بمفردهم. يجب أن ينتظروا حتى يتعافى المنسّق. وطوال تلك الفترة، تلك الصفوف غير متاحة — وقد يستمر ذلك دقائق أو أطول.
الاستخدام الفعلي: معاملات 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 في العمليات طويلة الأمد أو العابرة للخدمات.
بروتوكول الإتمام على ثلاث مراحل (3PC) — ملاحظة موجزة
يحاول بروتوكول 3PC حل مشكلة التعليق بإدراج مرحلة ما قبل الإتمام بين الإعداد والإتمام. لكنه يُدخل وضع فشل جديداً في حالة انقسام الشبكة (إتمام في جزء مقابل إلغاء في جزء آخر)، ونادراً ما يُستخدم عملياً. تبقى معظم الأنظمة مع 2PC وتستثمر في منسّقين عالي التوافر بدلاً من تعقيدات 3PC.
البدائل ومتى تستخدمها
بسبب تكاليف التعليق والأداء في 2PC، تقاربت الصناعة على هذه البدائل لمعظم سيناريوهات الخدمات المصغّرة:
- نمط Outbox مع CDC: اكتب الحدث في جدول
outboxضمن المعاملة المحلية نفسها مع بيانات العمل. تتولى عملية Change-Data-Capture (مثل Debezium) تتبع WAL ونشر الحدث. ذري داخل قاعدة بيانات واحدة؛ اتساق نهائي عبر الخدمات. - Sagas (تنسيق أو تنظيم): تقسيم المعاملة الموزعة إلى سلسلة من المعاملات المحلية، كل منها ينشر حدثاً. المعاملات التعويضية تتولى التراجع. مُغطّى في الدرس التاسع.
- Google Spanner / CockroachDB: قواعد بيانات موزعة تُطبّق بروتوكول إتمام موزع داخلياً، تُخفي التعقيد عن التطبيق وتحقق عزلاً قابلاً للتسلسل على نطاق عالمي.
النقاط الرئيسية
- يُنسّق 2PC إتماماً ذرياً عبر مشاركين مستقلين متعددين باستخدام بروتوكول إعداد → إتمام/إلغاء.
- المنسّق نقطة فشل واحدة؛ يجب أن يكون سجله مستداماً حتى يُعيد إرسال قراراته بعد الانهيار.
- يمسك المشاركون الأقفال بين المرحلة الأولى والثانية، مما يخلق نافذة تعليق تتناسب مع وقت تعافي المنسّق.
- XA هو التطبيق القياسي، وهو مدعوم في قواعد البيانات العلاقية والبرمجيات الوسيطة للمؤسسات.
- في معظم معماريات الخدمات المصغّرة الحديثة، يُفضّل نمط Outbox وSagas — يُقايضان الذرية الصارمة بالتوافر وقابلية التوسع.