استراتيجية التعامل مع تنازع الموارد بين المستأجرين في بيئة متعددة المستأجرين الكبيرة

السلام عليكم جميعاً،
أقوم بتشغيل منصة أتمتة متعددة المستأجرين فوق n8n وبدأت أواجه مشاكل حيث يؤثر عدد قليل من المستأجرين ذوي الحجم الكبير على تجربة الجميع الآخرين.
البنية الحالية:
قائمة الانتظار المشتركة

مجموعة العمال المشتركة

البنية التحتية المشتركة
المشاكل التي ألاحظها:
• يمكن لمستأجر واحد أن يفيض قائمة الانتظار
• سير العمل الذي يستغرق وقتاً طويلاً يؤخر الوظائف الأصغر
• المستأجرون الذين يستهلكون الواجهات البرمجية بكثافة يستهلكون قدرة عمل غير متناسبة
• زيادة الكمون للمستأجرين ذوي الحجم المنخفض
أهدافي هي:
• توزيع موارد عادل عبر المستأجرين
• منع مشاكل الجار المزعج
• الحفاظ على أداء يمكن التنبؤ به
• التوسع بدون الإفراط في توفير البنية التحتية
أنا أفكر في:
• قوائم انتظار خاصة بكل مستأجر
• قوائم انتظار ذات أولويات
• مجموعات عمال حسب مستوى المستأجر
• تحديد المعدل والحصص المسموحة
• بنية تحتية مخصصة للمستأجرين المؤسسيين
للفرق التي تشغل منصات سير عمل متعددة المستأجرين على نطاق واسع:
كيف تمنعون مشاكل الجار المزعج؟

ما رسالة الخطأ (إن وجدت)؟

يرجى مشاركة سير العمل الخاص بك

(حدد العقد على لوحتك واستخدم اختصارات لوحة المفاتيح CMD+C/CTRL+C و CMD+V/CTRL+V لنسخ ولصق سير العمل.)

شارك المخرجات المُرجعة من قبل العقدة الأخيرة

معلومات عن إعدادات n8n الخاصة بك

  • إصدار n8n:
  • قاعدة البيانات (الافتراضي: SQLite):
  • إعداد n8n EXECUTIONS_PROCESS (الافتراضي: own, main):
  • تشغيل n8n عبر (Docker, npm, n8n cloud, تطبيق سطح المكتب):
  • نظام التشغيل:

مرحباً @Keira_Becky الطريقة الأكثر شيوعاً هي الجمع بين حدود معدل الطلبات وعزل الطوابير وعزل العمال.

طابور مشترك + حدود لكل مستأجر + عمال مخصصون للمستأجرين الثقيلين

هذا يمنع مستأجراً واحداً من استهلاك جميع الموارد المتاحة.

الاستراتيجيات الشائعة
تطبيق حدود معدل الطلبات والحصص لكل مستأجر
استخدام طوابير الأولويات لمستويات الخدمة المختلفة
توجيه المستأجرين عالي الحجم إلى طوابير أو عمال مخصصين
إبقاء المستأجرين الأصغر على البنية التحتية المشتركة

بالنسبة للمستأجرين على نطاق واسع، تستخدم العديد من الفرق: مستأجر المؤسسة → طابور مخصص → مجموعة عمال مخصصة

تأكد من تجنب
طابور عام واحد بدون حدود
معاملة جميع المستأجرين بالتساوي بغض النظر عن الاستخدام
السماح بإعادة محاولة غير محدودة أو وظائف طويلة الأمد على العمال المشتركين

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

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

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

  • حد كل حاوية. حدود وحدة المعالجة المركزية والذاكرة لكل مثيل (compose أو k8s) بحيث حتى سير عمل هارب يقتصر على مستأجره الخاص، وليس المضيف.
  • عزل التنفيذ أيضاً. قم بتشغيل عقد الكود في عداء مهام جانبي خارجي لكل مثيل، بحيث يكون تنفيذ JS/Python محتوياً، وليس فقط الطابور.
  • قم بتصنيفها. لا تحتاج إلى مثيل واحد لكل مستأجر في اليوم الأول. يمكن للمستأجرين الصغار مشاركة مثيل؛ أعطِ المستأجرين الثقيلين والمؤسسيين مثيلهما الخاص. حتى المستوى المشترك أكثر صحة عند تقسيمه عبر عدة مثيلات من طابور عام واحد.
  • ضع مستوى تحكم فوق الأسطول. بعد حفنة من المثيلات، تحتاج إلى مكان واحد لترى فيه الأخطاء والصحة والعمليات التنفيذية عبر جميعها، والنشر والنسخ الاحتياطي دون الاتصال عبر SSH من صندوق إلى آخر.

مرحبا @Keira_Becky!

الرافعة الأكثر مباشرة في وضع قائمة الانتظار في n8n هي EXECUTIONS_CONCURRENCY_ACTIVE - اضبطها لكل حاوية عامل، وليس عالميًا. بالنسبة لمشكلة الجار المزعج، النمط الذي يعمل عمليًا هو: تشغيل مستويات عامل 2-3 بحدود تزامن مختلفة، ثم توجيه المستأجرين الثقيلين إلى مجموعة عاملهم الخاصة باستخدام بادئة مفتاح قائمة انتظار Redis منفصلة (تعيينها عبر QUEUE_BULL_PREFIX لكل عامل). يحصل المستأجرون عالي الحجم على عامل مخصص بـ EXECUTIONS_CONCURRENCY_ACTIVE أقل (على سبيل المثال 5)، وتحصل المستوى المشترك على عدد أكثر من العمال لكن كل واحد محدود بـ 10. سير العمل طويل المدى هو الحالة الأصعب - استخدم EXECUTIONS_TIMEOUT على مستوى المثيل و EXECUTIONS_TIMEOUT_MAX لكل سير عمل لمنع أي تنفيذ واحد من حجب العامل إلى الأبد. إذا كان اثنان أو ثلاثة مستأجرين يصلون باستمرار إلى الحد الأقصى لقائمة انتظارهم الخاصة، فإن ترقيتهم إلى مثيل n8n مخصص عادة ما يكون المسار الأنظف من محاولة عزلهم داخل مجموعة مشتركة واحدة.

واجهنا نفس المشكلة على منصة n8n+Postgres متعددة المستأجرين في بداية هذا العام — استدعاءات LLM تتجاوز Redis TTLs، ومستأجر بطيء واحد يحجب الجميع.

ما أوقف النزيف فعلاً: بادئات طابور BullMQ لكل مستوى مستأجر (QUEUE_BULL_PREFIX) + سقوف EXECUTIONS_CONCURRENCY_ACTIVE منفصلة لكل مجموعة عمل. قفل Redis هو المسار السريع. ثم Postgres UNIQUE (tenant_id, message_id) مع ON CONFLICT DO NOTHING كبوابة الإدامة لعدم التكرار — تلك هي طبقة الحقيقة عندما تتجاوز استدعاءات Gemini Redis TTL.

يستحق التحقق من طرفك: هل مدة TTL قفل Redis أطول من P99 لاستدعاء LLM لديك؟ عادة هنا يبدأ نزيف التنفيذ المكرر.

أيضاً — إذا ظل p95 LLM أقل من 2 ثانية و pool_wait مسطح، فالنزاع يكون في مكان آخر. عادة ما يكون QUEUE_RECOVERY_INTERVAL churn على المجدول.