انتقل إلى المحتوى الرئيسي
العودة إلى الرؤى
دفتر الحسابات10 دقائق قراءة

لماذا قواعد البيانات العامة هي الأساس الخاطئ لمعالجة المعاملات المالية

قانون أمدال وحدود قواعد البيانات العامة لأحمال التسوية عالية الإنتاجية. الحجة لصالح محركات مخصصة.

لماذا تفشل قواعد البيانات العامة في OLTP المالي


يمكن لـ PostgreSQL تخزين المعاملات المالية. يفعل ذلك بشكل موثوق لملايين الشركات. السؤال ليس ما إذا كان يمكنه تخزينها، بل ما إذا كان يمكنه فرض الثوابت المالية بالسرعة ومستوى الصحة المطلوبين لدفتر حسابات بنكي أساسي.

الإجابة، لفئة محددة ومعرفة جيدًا من أحمال العمل، هي لا. ليس لأن PostgreSQL معيب. لأنه صُمم لحل مشكلة مختلفة.

دفتر حسابات PostgreSQL

البنية الافتراضية: جدول transfers، جدول accounts بعمود balance (أو عرض مادي يجمع الترحيلات)، ومنطق على مستوى التطبيق لفرض القيد المزدوج. التحويلات INSERT فقط. تحديثات الأرصدة تُشغَّل بكود التطبيق أو مشغلات قاعدة البيانات.

عند 100 معاملة في الثانية مع 10,000 حساب موزع بالتساوي، يعمل هذا دون حوادث. الاستعلامات تكتمل في ميلي ثوانٍ أحادية الرقم. تنافس الأقفال ضئيل. النظام يجتاز كل اختبار.

يظهر السقف مع الحسابات الساخنة. حساب تحصيل رسوم تمسه 30% من جميع المعاملات. حساب تسوية يجمع المدفوعات الصادرة. حساب إيرادات المنصة الذي يستقبل كل تقسيم عمولة. هذه الحسابات موجودة في كل نظام مالي. إنها هيكلية وليست استثنائية.

عندما تحاول 50 معاملة متزامنة تحديث نفس رصيد الحساب، تصطف. يحصل PostgreSQL على قفل مستوى الصف (FOR UPDATE) على صف الرصيد. معاملة واحدة تتقدم؛ 49 تنتظر. تحت عزل SERIALIZABLE، المستوى الوحيد الذي يمنع جميع الشذوذات في أحمال العمل المالية، تضيف طبقة اكتشاف التعارض عبئًا إضافيًا. أعطال التسلسل تُشغِّل إعادات المحاولة. إعادات المحاولة تتراكم تحت الحمل.

التدهور غير خطي. عند 200 معاملة في الثانية، النظام بخير. عند 500، يتضاعف زمن p99. عند 1,000 مع حسابات ساخنة، يتجاوز معدل إعادة المحاولة 20% وتستقر الإنتاجية الفعلية. إضافة اتصالات تزيد الأمر سوءًا، المزيد من التنافس، المزيد من إعادات المحاولة، المزيد من العمل المهدر.

قانون أمدال مطبقًا على أحمال عمل دفتر الحسابات

صاغ جين أمدال هذا السقف رسميًا في 1967. إذا كان جزء S من حمل العمل متسلسلًا بطبيعته (لا يمكن توازيه)، فإن أقصى تسريع من N معالج متوازي هو:

Speedup = 1 / (S + (1 - S) / N)

مع اقتراب N من اللانهاية، يقترب التسريع من 1/S. إذا كان 5% من تحويلاتك تمس حسابًا ساخنًا يُسلسل الوصول، فأقصى تسريع هو 20 ضعفًا، بغض النظر عن العتاد. إذا 10%، السقف 10 أضعاف.

لأحمال العمل المالية بتوزيعات حسابات واقعية (Zipfian، عدد صغير من الحسابات يستقبل حصة غير متناسبة من الحركة)، الجزء المتسلسل عادة 5-15%. السقف حقيقي، ومنخفض.

الحلول البديلة مألوفة لأي شخص شغّل دفتر حسابات قائمًا على PostgreSQL على نطاق واسع:

التجزئة. تقسيم الحسابات عبر قواعد بيانات متعددة. التحويلات عبر الأجزاء (المرسل على الجزء A، المستلم على الجزء B) تتطلب التزامًا ثنائي المرحلة، بطيء ومعقد ووضع فشل جديد. العبء التشغيلي لإدارة حدود الأجزاء وإعادة التوازن والاستعلامات عبر الأجزاء غالبًا يتجاوز مكسب الأداء.

الاتساق النهائي. تخفيف مستوى العزل. قبول أن الأرصدة قد تكون خاطئة مؤقتًا. المطابقة لاحقًا. لنظام مدفوعات يعرض الأرصدة للعملاء، "خاطئ مؤقتًا" يعني "العميل يرى رقمًا ليس رصيده الفعلي." هذا ينتهك PSD2 المادة 87 (متطلبات تاريخ القيمة والتوفر) ويدمر ثقة المستخدم.

القفل المتفائل مع إعادات المحاولة. قبول التنافس. إعادة محاولة المعاملات الفاشلة. تعيين ميزانية إعادة محاولة. الأمل في أن التنافس يُحل قبل استنفاد الميزانية. عند الحمل العالي، يتدهور هذا إلى عاصفة إعادة محاولة حيث معظم عمل قاعدة البيانات مهدر.

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

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

البديل المصمم خصيصًا

محرك تسوية مصمم لـ OLTP المالي يتخذ ثلاثة خيارات لا تستطيع قاعدة البيانات العامة اتخاذها دون التخلي عن العمومية:

سجلات بحجم ثابت. كل حساب: 128 بايت، محاذاة لخط التخزين المؤقت. كل تحويل: 128 بايت، محاذاة لخط التخزين المؤقت. لا حقول متغيرة الطول. لا TOAST. لا صفحات فائضة. محرك التخزين يحسب موقع أي سجل على القرص بالحساب، لا تجاوز B-tree، لا بحث في الفهرس. الوصول التسلسلي مُعظَّم. الإدخال/الإخراج العشوائي مُلغى.

المعالجة الدفعية بدلًا من قفل مستوى الصف. المحرك يجمع التحويلات في دفعات (حتى 8,190 لكل دفعة) ويعالجها في تمريرة واحدة. لا أقفال مستوى صف لأنه لا وصول متزامن لصفوف فردية. الدفعة هي وحدة الذرية.

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

ثوابت مفروضة بالمحرك. القيد المزدوج ليس مكتبة أو مشغلًا. إنه قيد بروتوكول. تحويل حيث sum(debits) ≠ sum(credits) يُرفض بواسطة المحرك قبل أن يصل إلى التخزين. تحويل يسحب على المكشوف من حساب (عندما يكون علم debits_must_not_exceed_credits مضبوطًا) يُرفض. إلغاء التكرار على مستوى البروتوكول: معرف تحويل 128 بت يمنع إعادة التشغيل دون مفاتيح تكرار منع على مستوى التطبيق.

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

الأداة المناسبة لكل طبقة

هذه ليست حجة ضد PostgreSQL. PostgreSQL هو الخيار الصحيح لـ:

نوع البياناتلماذا PostgreSQL
سجلات العملاءعلائقي، قابل للاستعلام، حقول متغيرة الطول، بحث نص كامل
بيانات KYC/KYBبنى متداخلة معقدة، دعم JSON، مفاتيح خارجية للعملاء
التكوينمفتاح-قيمة مع قيود، مشغلات تدقيق، RLS لكل مستأجر
ملفات تعريف الولايات القضائيةعلائقي مع تقويمات عطلات، قواعد أيام العمل
سجلات التدقيقإلحاق فقط بسلاسل هاش، قابلة للاستعلام بمعرف الارتباط
بيانات وصفية للمعاملاترموز أسباب ISO، مراجع خارجية، مسار تدقيق الترحيل

PostgreSQL يتعامل مع كل هذا جيدًا. SQL هي لغة الاستعلام المناسبة للتحليل المخصص والتقارير والأدوات التشغيلية.

الحجة ضد استخدام PostgreSQL لشيء واحد محدد: التسوية المالية عالية الإنتاجية، خالية التنافس، المتسلسلة بصرامة. لحمل العمل هذا، وهذا الحمل فقط، يقدم محرك مصمم خصيصًا خصائص لا يمكن لـ PostgreSQL مطابقتها دون تنازلات تقوض الصحة.

البنية: طبقتا تخزين، كل منهما مُحسَّنة لحمل عملها.

PostgreSQLتخزين علائقي

بيانات المجال، البيانات الوصفية، التكوين: سجلات العملاء، بيانات KYC/KYB، سجلات التدقيق، بيانات وصفية للمعاملات، ملفات تعريف الولايات القضائية. قوة SQL الكاملة للاستعلامات والتقارير.

Settlement EngineOLTP مصمم خصيصًا

عمليات دفتر الحسابات فقط: أرصدة الحسابات، تنفيذ التحويلات، فرض القيد المزدوج، الالتزام ثنائي المرحلة. زمن استجابة دون الميلي ثانية، صفر تنافس.

PostgreSQL يفعل ما يجيده: تخزين واستعلام البيانات المنظمة بقوة SQL الكاملة. محرك التسوية يفعل شيئًا واحدًا: نقل الأموال بين الحسابات بتسلسل صارم، صفر تنافس، وثوابت مفروضة بالمحرك. لا نظام يحاول أن يكون الآخر.

كيف تقيّم

ثلاثة أسئلة لأي تقييم تخزين دفتر حسابات. الإجابات قابلة للقياس.

1. ماذا يحدث عندما تصطدم 100 تحويل متزامن بنفس الحساب؟

قس زمن p99، وليس p50. P50 يخبرك بالحالة النموذجية. P99 يخبرك بما يحدث تحت التنافس، وهو السيناريو الوحيد المهم للحسابات الساخنة. إذا تدهور p99 بأكثر من 10 أضعاف تحت حمل الحسابات الساخنة، النظام لديه سقف تنافس.

2. هل يمكن لخطأ في كود تطبيقك إنشاء أموال؟

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

3. ما استراتيجية إلغاء التكرار لديك؟

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


اقرأ المزيد: دفتر الحسابات | التسوية الحتمية


المصادر:

  • Amdahl, Gene M. "Validity of the single processor approach to achieving large scale computing capabilities." AFIPS '67, 1967.
  • توثيق PostgreSQL: قفل مستوى الصف، العزل المتسلسل (https://www.postgresql.org/docs/current/transaction-iso.html)
  • PSD2، التوجيه 2015/2366، المادة 87 (تاريخ القيمة وتوفر الأموال)
  • "Scalability! But at what COST?" (McSherry et al., USENIX HotOS'15)، لماذا التوسع الأفقي ليس دائمًا الإجابة لـ OLTP كثيف الكتابة