التنفيذات المتوازية باستخدام عقدة Oracle Database الأصلية تفتح عدداً كبيراً من جلسات Oracle المتزامنة، وتبدأ قاعدة البيانات في معاناة من تنافس المزالج.
المشكلة الأساسية هي أن العدد الكبير من اتصالات Oracle التي يفتحها n8n بشكل متزامن يغمر قاعدة البيانات. يخطط كل اتصال n8n إلى جلسة خادم مخصصة على Oracle، لذلك عندما تعمل العديد من التنفيذات بالتوازي، يتم فتح عشرات الجلسات في نفس الوقت وتبدأ النسخة في المعاناة من تنافس المزالج. هدفي هو تحديد عدد جلسات Oracle التي يمكن أن تكون مفتوحة في نفس الوقت حتى لا تكون قاعدة البيانات مغمورة بالعمل.
أنا أعمل في وضع الطابور مع 3 حاويات عمل و N8N_WORKER_CONCURRENCY=10 (حتى ~30 تنفيذ متزامن).
فهمي الحالي (يرجى تصحيحي): في وضع الطابور، كل عامل هو عملية منفصلة، لذا أفترض أن مجمع اتصالات Oracle يتم إنشاؤه لكل عامل، مما يعني أن Pool Max ينطبق لكل عامل وليس عالمياً.
الأسئلة:
هل يتم إنشاء مجمع اتصالات Oracle لكل عملية عامل (بحيث يكون Pool Max لكل عامل)، أم أنه مشترك بطريقة ما؟
أثناء التنفيذات المتوازية، هل تتحقق العقدة من اتصال واحد لكل تنفيذ (1:1)، أم لكل استعلام / لكل عنصر؟
لتقليل جلسات Oracle المتزامنة، ما هو النهج الموصى به: خفض N8N_WORKER_CONCURRENCY، أو تقليل عدد العمال، أو خفض Pool Max، أو مزيج منها؟ أي واحدة هي الرافعة الأساسية الصحيحة؟
إذا خفضت Pool Max، هل تنتظر طلبات الاتصال الإضافية في طابور وتنتظر اتصالاً مجانياً بدلاً من إغمار قاعدة البيانات؟
هل تعمل هذه العقدة node-oracledb في وضع Thin أم Thick بشكل افتراضي؟ إذا كانت Thick، هل يحتاج UV_THREADPOOL_SIZE إلى ضبط إلى جانب Pool Max؟
ما رسالة الخطأ (إن وجدت)؟
لا يوجد خطأ على مستوى التطبيق في n8n. الأعراض موجودة على جانب Oracle: عشرات الجلسات النشطة التي تقوم بتشغيل نفس SQL_ID بالتزامن، عالقة على latch: cache buffers chains و cpu runqueue. عينة مختصرة:
SID SERIAL USER PROG TYPE STATE WAIT_CLASS EVENT
... 3332220 APPUSER node DED CPU Other cpu runqueue
... 3334370 APPUSER node DED CPU Concurrency latch: cache buffers chains
... 3331979 APPUSER node DED CPU Other latch free
... 3332223 APPUSER node DED CPU Other PGA memory operation
(عشرات أخرى، نفس SQL_ID، نفس أحداث الانتظار)
يرجى مشاركة سير العمل الخاص بك
(غير ذي صلة بهذا السؤال. المشكلة تتعلق بتزامن الاتصال/الجلسة، وليس سير عمل محدد.)
مشاركة المخرجات التي يرجعها آخر عقدة
(غير قابل للتطبيق.)
تكوين مجمع Oracle الحالي (لكل بيانات اعتماد)
Pool Min: 0
Pool Max: 600
Pool Increment: 5
Pool Maximum Session Life Time: 3600
Pool Connection Idle Timeout: 180
Connection Class Name: غير محدد
Connection Timeout: 0
Transport Connection Timeout: 20
Keepalive Probe Interval: 60
معلومات عن إعداد n8n الخاص بك
إصدار n8n: Version 2.20.7-exp.0
إصدار عقدة Oracle Database: Oracle Database node version 1 (Latest)
قاعدة البيانات (قاعدة بيانات n8n الخاصة): PostgreSQL 16
إصدار Oracle Database (قاعدة البيانات المستهدفة):
وضع EXECUTIONS_PROCESS / n8n: وضع الطابور (Redis/Bull)، 3 عمال، N8N_WORKER_CONCURRENCY=10
افتراضك صحيح. في وضع الطابور، كل عامل عملية منفصلة، لذا المجموعة خاصة بكل عامل وليست مشتركة، مما يعني أن Pool Max 600 الخاص بك يصل فعليا إلى 1800 عبر 3 عمال.
تحقق العقدة اتصال واحد لكل تنفيذ، وليس لكل استعلام أو عنصر، لذا كل تنفيذ يحتفظ باتصال واحد. مع التزامن 10، العامل لا يحتاج أبدا لأكثر من ~10.
إذن Pool Max هو الرافعة الأساسية لديك: اضبطه لكل عامل حول التزامن الخاص بك (10-15)، والجلسات الإجمالية تصل إلى حوالي عدد العمال مضروبا في هذا، تقريبا 30-45. عندما تكون المجموعة في الحد الأقصى، يضع node-oracledb طلبات الاتصال في قائمة الانتظار حتى يتحرر واحد، بدلا من إرهاق قاعدة البيانات.
يعمل بوضع رقيق بشكل افتراضي، لذا UV_THREADPOOL_SIZE مهم فقط إذا فعّلت الوضع الثقيل.
تحديث بعد المزيد من التحقيق. قمت بخفض Pool Max وبدأت الحصول على NJS-076: connection request rejected. Pool queue length "queueMax" 500 reached. إذاً الطلبات لا تنتظر في قائمة الانتظار بشكل غير محدود. يقوم node-oracledb بوضع استدعاءات getConnection() المعلقة في قائمة الانتظار فقط حتى queueMax (الافتراضي 500)، ورفض أي شيء يتجاوز ذلك.
اتضح أن السبب في امتلاء قائمة الانتظار هو هندستي المعمارية، وليس الحد الأقصى لكل عنصر. سير العمل الأصلي الخاص بي يجلب 1000 سجل ويرسلها إلى سير عمل فرعي مع تعطيل “Wait For Sub-Workflow Completion”. اعتقدت أن N8N_WORKER_CONCURRENCY (3 عمال × 10) سيقيد هذا إلى ما يقرب من 30 بالتزامن والباقي سيانتظر دوره.
لكن وفقاً لوثائق n8n، فإن حد التزامن ينطبق فقط على تنفيذات الإنتاج التي تبدأ من عقدة مشغل أو webhook، ولا ينطبق بشكل صريح على تنفيذات سير العمل الفرعي. سير العمل الأصلي (تنفيذ مشغل واحد) مقيد بالتدفق، لكن 1000 تنفيذ لسير عمل فرعي الذي يولده غير مقيد. يتم إرسالها بشكل كبير، وكل واحد يطلب اتصالاً بـ Oracle في نفس الوقت تقريباً، تمتلئ قائمة انتظار المجموعة إلى 500، والباقي يتم رفضه بـ NJS-076. الرقم الذي يطابق الافتراضي 500 يؤكد هذا.
إذاً هناك حقاً قائمتا انتظار منفصلتان هنا: قائمة انتظار تنفيذ n8n (Redis/Bull) وقائمة انتظار مجموعة node-oracledb. حد التزامن يتحكم فقط في الأول، وليس لسير العمل الفرعي.
أسئلة:
هل هذا السلوك المتوقع، أن تنفيذات سير العمل الفرعي التي تم تشغيلها مع تعطيل “Wait For Sub-Workflow Completion” تتجاوز حد التزامن بالكامل؟ هل يوفر N8N_WORKER_CONCURRENCY أي تدفق للتحكم في وضع قائمة الانتظار، أم لا على الإطلاق؟
بالنظر إلى ذلك، ما هو النمط الموصى به للتحكم في الإرسال حتى لا أفيض مجموعة الاتصالات: الاحتفاظ بـ “Wait For Sub-Workflow Completion” مفعلاً، استخدام Loop Over Items / Split in Batches في الأصل لإرسال دفعات أصغر، أو تجميع السجلات بحيث يتم تشغيل عدد أقل من تنفيذات سير العمل الفرعي؟
هل queueMax قابل للتكوين من خلال بيانات اعتماد Oracle على الإطلاق؟ إنه ليس في حقول بيانات الاعتماد الحالية، لذا أفترض أنه ثابت عند 500.
للأسف، خطتي هي التحكم في الانتشار على جانب الأصل بدلاً من الاعتماد على Pool Max، لأن خفض Pool Max فقط ينقل الفشل من “قاعدة البيانات مثقلة” إلى “رفض قائمة انتظار المجموعة”. سعيد بسماع ما إذا كان هناك نهج أنظف.
مرحبا بك في مجتمع n8n @giovanni.tavares
توصي n8n بتزامن 5 أو أكثر لكل عامل (worker)؛ القيم المنخفضة جدًا مع عدد كبير من العمال قد تستنزف مجموعة اتصالات قاعدة البيانات. ستكون صيغة الجلسات القصوى التقريبية: عدد_العمال × Pool Max Configuring queue mode | n8n Docs
شكراً @tamy.santos. صيغة workers × Pool Max تؤكد أن المجموعة خاصة بكل عامل، وهو ما يتطابق مع ما قاله @achamm.
الجزء الذي لا أزال عالقاً فيه هو أن هذه الصيغة تصف الحد الأقصى للجلسات المُنشأة في الحالة المستقرة، لكن فشلي مختلف. NJS-076 هو قائمة انتظار طلبات الاتصال (queueMax 500) التي تامتلئ لأن الطلبات تصل أسرع من تحرر الاتصالات، وليس تجاوز الحد الأقصى للجلسة. الجزء الصعب هو أن خفض Pool Max يجعل NJS-076 أكثر احتمالاً (عدد أقل من الاتصالات لامتصاص الفجوة)، بينما زيادته تعيد المشكلة الأصلية المتمثلة في إرهاق قاعدة البيانات. لذلك لا توجد قيمة Pool Max مستقرة ما لم يتم خنق فجوة طلبات الاتصال نفسها.
تأتي هذه الفجوة من سير العمل الأساسي الذي يرسل ~1000 تنفيذ لسير عمل فرعي مع تعطيل “الانتظار حتى اكتمال سير العمل الفرعي”، وطبقاً للمستندات فإن حد التزامن الإنتاجي لا ينطبق على تنفيذات سير العمل الفرعي، لذا فهي غير محدودة بتزامن العامل.
لذا فإن خطتي هي خنق الجانب الأساسي بدلاً من ضبط Pool Max: إما الاحتفاظ بـ “الانتظار حتى اكتمال سير العمل الفرعي” مفعلاً، أو استخدام Loop Over Items / Split in Batches لإرسالها على دفعات أصغر، أو تجميع السجلات بحيث يتم تشغيل عدد أقل من أسالب سير العمل الفرعي.
هل لدى أحد نمط موصى به لخنق إرسال سير العمل الفرعي في وضع قائمة الانتظار، نظراً لأن حد التزامن لا يغطيها؟ يبدو أن هذا هو الرافعة الحقيقية هنا.
تُرسل عقدة “Execute Workflow” المعينة على “run once for each item” تنفيذ سير عمل فرعي واحد لكل سجل، أي ~1000 تنفيذ سير عمل فرعي.
تم تعطيل “Wait For Sub-Workflow Completion”، لذا يطلق الأساسي جميعها دون انتظار.
سير العمل الفرعي (تنفيذ واحد لكل سجل)
يقوم بتشغيل عدة استعلامات Oracle مقابل نفس قاعدة البيانات. يتم تشغيلها بالتسلسل في تدفق خطي، لذا يحتفظ التنفيذ الواحد بتوصيل واحد في الوقت الأقصى. لا يؤدي عدد الاستعلامات لكل تنفيذ إلى مضاعفة الاتصالات المتزامنة؛ ما يحرك التزامن هو عدد تنفيذات سير العمل الفرعي التي تعمل في نفس الوقت.
البنية التحتية
وضع الطابور (Queue mode)، Redis/Bull، 3 حاويات عاملة، N8N_WORKER_CONCURRENCY=10.
عقدة قاعدة بيانات Oracle الأصلية، الإصدار 2.20.7-exp.0.
المشكلة هي أن ~1000 تنفيذ سير عمل فرعي لا تقتصر على حد التزامن (لأنها لا تنطبق على تنفيذات سير العمل الفرعي)، لذا تضرب مجموعة Oracle في دفعات وتفيض طابور طلب الاتصال (queueMax 500)، مما يعطي NJS-076.
يبدو أن هذا مشكلة حد التزامن أكثر من كونها مشكلة استعلام Oracle. مع وضع الطابور وعدة عمال، أفترض أن كل عامل يمكنه إنشاء مجموعته الخاصة من الجلسات حتى يثبت خلاف ذلك، ثم قلل التزامن على مستوى العامل أو وجّه العمل الثقيل المتعلق بـ Oracle عبر تدفق فرعي محكوم. يجب أن تكون حذراً مع إعادة المحاولات هنا لأنها يمكن أن تجعل ارتفاع الجلسة أسوأ. هل اختبرت نفس سير العمل مع عامل واحد وتزامن منخفض للتأكد من انخفاض عدد الجلسات؟