معالجة ديد لوك قاعدة البيانات (PostgreSQL Deadlock) في جدول الطلبات وعناصر السلة وقت ضغط المتاجر
الحل المعماري الحاسم لمنع تعليق جدول الطلبات وأخطاء Deadlock Detected في PostgreSQL تحت ضغط الحملات بالسعودية والخليج
الخلاصة التنفيذية (BLUF): وقت حملات التخفيضات الضخمة وعروض اليوم الوطني ويوم التأسيس، تتلقى المتاجر آلاف الطلبات المتزامنة في الثانية. عندما تحاول عمليتا شراء مختلفتان حجز المخزون وتحديث جدول عناصر الطلب (order_items) بترتيب عشوائي غير موحد، تدخل قاعدة بيانات PostgreSQL في حلقة قفل مفرغة تنتهي برسالة الخطأ القاتلة: ERROR: deadlock detected (SQLSTATE 40P01)، وتفشل عملية الشراء للعميل رغم خصم المبلغ من بطاقته في بعض الحالات. الحل المعماري الصارم هو فرز معرّفات المنتجات (Product IDs) تصاعدياً دائماً قبل طلب القفل SELECT ... FOR UPDATE، وتقصير مهلة deadlock_timeout إلى 100ms، واستخدام الأقفال الاستشارية لتسريع المعالجة دون قفل الجداول بالكامل.
أعراض المشكلة في بيئة الإنتاج بالمملكة والخليج
أثناء ذروة الشراء في المتاجر الكبرى والمنصات الوسيطة في الرياض وجدة ودبي، تظهر المؤشرات التالية:
- امتلاء سجلات PostgreSQL بخطأ:
ERROR: deadlock detected: مما يجبر قاعدة البيانات على إنهاء (Abort) إحدى العمليتين عشوائياً لفك التعليق. - ظهور صفحة بيضاء أو خطأ 504 Gateway Timeout للعميل وقت الضغط على زر "إتمام الشراء": مما يرفع معدل سلات الشراء المتروكة بنسبة تتجاوز 40%.
- تراكم العمليات المعلقة واستنزاف مجمع الاتصالات (PgBouncer Pool Exhaustion): حيث تظل خيوط المعالجة تنتظر فك الأقفال حتى يسقط السيرفر بأكمله.
السبب الجذري لخلل الديد لوك (Deadlock)
يحدث الديد لوك عندما تقوم العملية (A) بقفل المنتج رقم 10 ثم تطلب قفل المنتج 25، بينما في نفس اللحظة بالمللي ثانية تقوم العملية (B) بقفل المنتج 25 وتطلب قفل المنتج 10. لا يمكن لأي من العمليتين المضي قدماً، فتتدخل قاعدة البيانات بعد مهلة التعليق لإلغاء إحداهما. السبب الأساسي هو إضافة عناصر السلة بترتيب عشوائي يحدده العميل بدلاً من فرزها في الباك إند بترتيب رقمي ثابت.
المعمارية الهندسية والكود التنفيذي لحل المشكلة
للقضاء على الـ Deadlock بنسبة 100%، نطبق القواعد الهندسية التالية في محرك الحجز:
-- 1. تقليص مهلة الديد لوك لمنع تجميد الاتصالات
SET LOCAL deadlock_timeout = '100ms';
SET LOCAL statement_timeout = '2500ms';
-- 2. القاعدة الذهبية: قفل صفوف المنتجات دائماً بترتيب تصاعدي موحد (ORDER BY id ASC)
-- يتم فرز مصفوفة المنتجات في تطبيق Node.js/Python قبل إرسالها إلى قاعدة البيانات:
SELECT id, stock_quantity
FROM inventory
WHERE id = ANY($1::bigint[])
ORDER BY id ASC
FOR UPDATE;
-- 3. إدراج عناصر الطلب في جدول order_items بعد ضمان حجز المخزون دون أي تعليق
INSERT INTO order_items (order_id, product_id, quantity, unit_price)
SELECT $1, unnest($2::bigint[]), unnest($3::int[]), unnest($4::numeric[]);
المؤشرات التقنية التي يجب مراقبتها في بروميثيوس وجرافانا
pg_stat_database_deadlocks == 0: يجب أن يظل معدل الديد لوك في الدقيقة صفراً تماماً.pg_stat_activity_waiting_locks < 3: ألا تتجاوز العمليات المنتظرة للأقفال 3 عمليات لحظياً.checkout_p99_latency_seconds < 0.20: إتمام حجز الطلب وقفل المخزون في أقل من 200 مللي ثانية.
هل تواجه أخطاء ديد لوك (Deadlock) أو بطء في قاعدة بيانات متجرك وقت الضغط؟
أقدم استشارات متقدمة لهندسة قواعد بيانات PostgreSQL، ضبط الـ Locks، إعداد مجمعات الاتصال PgBouncer، وتفادي انهيار السيرفرات في الرياض، جدة، ودبي.
استشارات هندسة البنية التحتية والأنظمة
هل تحتاج مهندس بنية تحتية أول لضبط أداء واستقرار خوادمك؟
من خوادم Kubernetes المستقلة ونظام Talos Linux إلى معالجة اختناقات PostgreSQL وحلول الذكاء الاصطناعي السيادي، أعمل مباشرة مع فرق الإنتاج لبناء بيئات تقنية متماسكة وعالية الاعتمادية.