لماذا يتعطل n8n بسبب الذاكرة، وليس للسبب الذي تظنه
V8، محرك JavaScript المدمج في Node.js، يملك حداً لـheap مستقلاً عن ذاكرة RAM الفعلية. يتراوح هذا الحد افتراضياً بين 512 ميغابايت و1.5 غيغابايت بحسب إصدار Node والمنصة — على VPS بـ4 غيغابايت أو 8 غيغابايت، الجهاز لا ينفد من الذاكرة، لكن عملية V8 تنفد. إضافة ذاكرة RAM للخادم لا تغير شيئاً دون NODE_OPTIONS=--max-old-space-size.
السبب الثاني الشائع: في وضع main (الافتراضي)، ينفذ n8n سير العمل في نفس العملية التي تخدم webhook والـAPI. سير عمل ثقيل البيانات — تحويل CSV، تجميع آلاف الصفوف، استدعاء GPT في حلقة — يستأثر بـheap أثناء التنفيذ. إذا تراكمت عدة طلبات، يُبلغ حد V8 وتُقتل العملية.
السبب الثالث الأدق: تتراكم المهام في الذاكرة عند تفعيل وضع queue دون عمال مخصصين. تُفرغ الـqueue (Redis أو BullMQ) العملية الرئيسية من التنفيذات، لكن إذا لم يستهلك أي worker المهام فعلاً، تتراكم، وتبقى callback في انتظار، ويكبر heap.
علامات تؤكد عطل OOM في n8n
- رسالة الخروج الدقيقة:
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory في سجلات الحاوية (docker logs n8n) - توقف صامت تحت systemd: تعيد الخدمة التشغيل تلقائياً دون أثر إذا كان
Restart=always مفعلاً — تحقق عبر journalctl -u n8n --since "1 hour ago" - OOM kill النواة:
dmesg | grep -i oom يظهر Killed process <pid> (node) قبل إعادة التشغيل، بمعزل عن Node - ارتباط بسير عمل ثقيل: يحدث العطل دائماً أثناء تنفيذات من نوع «معالجة ملف» أو «حلقة على آلاف العناصر»
- heap ثابت لساعات ثم ارتفاع مفاجئ: سير عمل يُشغَّل دورياً يتراكم فيه closure غير محررة — يرتفع heap في كل تشغيل ولا يعود كاملاً
- حمل ذاكرة طبيعي في htop: ذاكرة RAM النظام غير مستنفدة وقت العطل، ما يؤكد أن المشكلة في V8 لا الجهاز
المتطلبات قبل التدخل
تفترض هذه الخطوات أن n8n يعمل بالفعل على VPS عبر Docker Compose. إن لم يكن كذلك، يغطي مقال installer-n8n-vps النشر الكامل من الصفر — عد إلى هنا بعد تشغيل الخادم.
ما تحتاجه لتطبيق الإصلاحات:
- وصول SSH root إلى VPS وملف docker-compose.yml قابل للتحرير
- ذاكرة متاحة: حد V8 بـ4096 ميغابايت (--max-old-space-size=4096) يستلزم 6 غيغابايت RAM على الأقل لترك هامش للنظام والعمال وRedis
- Redis منشور مسبقاً إذا انتقلت لوضع queue — redis:7-alpine كافٍ للاستخدام الفردي
- إصدار n8n 1.0 أو أعلى: الفصل بين main/worker متاح منذ الإصدار 0.214 لكنه مستقر في الإنتاج فقط من 1.0
- نسخة احتياطية للقاعدة قبل أي تعديل على Compose — جداول credentials والتنفيذات ليست ضمن صورة Docker
إصلاح OOM: من التشخيص إلى الإعداد الثابت
تأكيد السبب من السجلات
اقرأ آخر 200 سطر من الحاوية وقت العطل:
docker logs n8n --tail 200 2>&1 | grep -E "FATAL|heap|OOM|Killed"إن رأيت
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory فالمشكلة في V8. إن رأيت Killed وحده دون رسالة Node، فهو OOM killer النواة — قد يتزامن الاثنان في نفس الحادثة.تعيين حد V8 عبر NODE_OPTIONS
في
docker-compose.yml، أضف متغير البيئة NODE_OPTIONS إلى خدمة n8n. القيمة الموصى بها حسب RAM الـVPS:- VPS 4 غيغابايت:
--max-old-space-size=2048
- VPS 8 غيغابايت: --max-old-space-size=4096
- VPS 16 غيغابايت: --max-old-space-size=8192القاعدة: احجز ما يقارب نصف الذاكرة المتاحة بعد النظام والخدمات المساندة (Redis، البروكسي). لا تتجاوز 70% من إجمالي الـRAM.
services: n8n: image: n8nio/n8n:latest environment: - NODE_OPTIONS=--max-old-space-size=4096 # ... متغيرات أخرىالتحقق من قراءة القيمة فعلياً
بعد
docker compose up -d، تحقق من أن Node يقرأ الحد:docker exec n8n node -e "const v8=require('v8'); console.log(v8.getHeapStatistics().heap_size_limit / 1024 / 1024, 'MB')"يجب أن تقترب القيمة المعروضة من
--max-old-space-size. إن عرضت 512 أو 1500 مجدداً، فمتغير البيئة غير مُمرَّر للعملية — تحقق من أن NODE_OPTIONS في قسم environment: للخدمة.الانتقال إلى وضع queue مع Redis
وضع main (الافتراضي) ينفذ كل شيء في عملية واحدة. للخوادم التي تتعامل مع أكثر من 20 سير عمل متزامناً أو حمولات كبيرة، افصل الأدوار:
services: redis: image: redis:7-alpine restart: unless-stopped volumes: - redis_data:/data n8n: image: n8nio/n8n:latest environment: - NODE_OPTIONS=--max-old-space-size=2048 - EXECUTIONS_MODE=queue - QUEUE_BULL_REDIS_HOST=redis - QUEUE_BULL_REDIS_PORT=6379 depends_on: - redis ports: - "5678:5678" n8n-worker: image: n8nio/n8n:latest command: worker environment: - NODE_OPTIONS=--max-old-space-size=4096 - EXECUTIONS_MODE=queue - QUEUE_BULL_REDIS_HOST=redis - QUEUE_BULL_REDIS_PORT=6379 depends_on: - redis scale: 2 volumes: redis_data:تصبح خدمة n8n هي العملية الرئيسية (API + واجهة + webhook) بحد معتدل. تتولى خدمة n8n-worker التنفيذات بحد أعلى.
scale: 2 يشغل عاملَين — اضبط حسب احتياجاتك.فصل عملية webhook إذا تطلب الحجم ذلك
على الخوادم التي تستقبل webhook متوازياً بكثرة، قد تكون العملية الرئيسية مشبعة دون تنفيذ سير عمل. n8n يوفر وضع webhook مخصصاً:
n8n-webhook: image: n8nio/n8n:latest command: webhook environment: - NODE_OPTIONS=--max-old-space-size=1024 - EXECUTIONS_MODE=queue - QUEUE_BULL_REDIS_HOST=redis - QUEUE_BULL_REDIS_PORT=6379 - N8N_DISABLE_UI=true depends_on: - redis ports: - "5679:5678"ثم اضبط البروكسي لتوجيه
/webhook/ إلى المنفذ 5679 وباقي الطلبات إلى المنفذ 5678 للعملية الرئيسية. وضع webhook متاح من n8n 1.0.تفعيل garbage collection الصريح للسير الثقيلة
للسير العمل التي تعالج ملفات كبيرة أو حلقات طويلة، يمكنك مساعدة V8 على تحرير الذاكرة بشكل أكثر حدة:
NODE_OPTIONS="--max-old-space-size=4096 --expose-gc"هذا يكشف
global.gc() — يمكن لـn8n استدعاؤه بين خطوات سير العمل. اجمعه مع EXECUTIONS_DATA_SAVE_ON_SUCCESS=none إن لم تحتج لتاريخ التنفيذ: بيانات التنفيذ المحتجزة كثيراً ما تمثل 30-50% من heap.مراقبة heap بعد الإصلاح
فعّل مقاييس n8n لمتابعة heap دون تدخل يدوي:
N8N_METRICS=true N8N_METRICS_PREFIX=n8n_نقطة الوصول
/metrics (المنفذ 5678) تكشف حينئذٍ nodejs_heap_size_used_bytes وnodejs_heap_size_total_bytes، متوافقة مع Prometheus. لوحة Grafana بسيطة على هذين المقياسين ستنبهك قبل العطل التالي.
تحديد حجم حمولة التنفيذ
المعامل EXECUTIONS_DATA_MAX_SIZE (بالبايت، لا حد افتراضي) يقطع التنفيذ قبل أن يُطفح heap. القيمة الموصى بها للخوادم العامة: 16777216 (16 ميغابايت). سير عمل يتجاوز هذا الحد يفشل بشكل نظيف بدلاً من قتل العملية بأسرها. اجمعه مع EXECUTIONS_DATA_PRUNE=true وEXECUTIONS_DATA_MAX_AGE=168 (أسبوع واحد) لتجنب تراكم بيانات التنفيذات السابقة.
الإعداد بعد الإصلاح: متغيرات البيئة المفيدة
بعد حل OOM، هذه المتغيرات تعزز استقرار الخادم:
- N8N_DEFAULT_BINARY_DATA_MODE=filesystem — يخزن الملفات الثنائية على القرص لا في الذاكرة؛ ضروري لسير العمل التي تعالج ملفات CSV أو PDF كبيرة
- OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS=true — التنفيذات اليدوية (المُشغَّلة من المحرر) تمر بالعمال أيضاً، تجنباً للضغط على heap العملية الرئيسية أثناء الاختبار
- N8N_RUNNERS_ENABLED=true وN8N_RUNNERS_MAX_CONCURRENCY=5 — يفعّل task runner التجريبي (n8n 1.10 فأعلى) الذي يعزل كل تنفيذ في عملية فرعية، منعاً لسير عمل واحد من استنفاد الـheap بأسره
- DB_POSTGRESDB_* — الترحيل من SQLite إلى PostgreSQL للخوادم ذات الحجم الكبير: SQLite يُسلسل جميع القراءات/الكتابات وقد يُعيق العمال، مما يكثف ضغط الذاكرة
استكشاف الأخطاء — أخطاء حقيقية وأسبابها
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
السبب المباشر: بلغ heap V8 حده. الحل: أضف NODE_OPTIONS=--max-old-space-size=<n> في متغيرات البيئة للحاوية، بقيمة مُعايَرة على الذاكرة المتاحة (الخطوة 2).
Killed في السجلات دون رسالة Node
السبب: قتل OOM killer لنواة Linux العملية قبل أن يتمكن V8 من إصدار رسالته. يحدث عند استنفاد الذاكرة الفعلية — مختلف عن عطل V8 الخالص. تحقق بـdmesg | grep -i oom. قلل --max-old-space-size أو أضف RAM، وفعّل EXECUTIONS_DATA_SAVE_ON_SUCCESS=none لتخفيف البصمة.
العمال لا يستهلكون المهام رغم EXECUTIONS_MODE=queue
السبب الشائع: DB_TYPE ومتغيرات قاعدة البيانات غير مُمرَّرة للعمال. كل خدمة في Compose يجب أن تحمل متغيرات الاتصال الخاصة بها. تحقق بـdocker exec n8n-worker env | grep DB_.
heap يرتفع بعد كل تشغيل ولا يعود
السبب: closure تحتجز مرجعاً لمصفوفة كبيرة بين التنفيذات. فعّل --expose-gc في NODE_OPTIONS وأضف EXECUTIONS_DATA_SAVE_ON_SUCCESS=none. إن استمر، انتقل لوضع task runner (N8N_RUNNERS_ENABLED=true).
Error: Redis connection failed بعد الانتقال لوضع queue
السبب: QUEUE_BULL_REDIS_HOST يشير إلى localhost بدلاً من اسم خدمة Docker. في شبكة Compose، تصل العملية الرئيسية والعمال إلى Redis باسم الخدمة (redis في المثال)، لا 127.0.0.1.
المصادر والخطوات التالية
توثيق n8n الرسمي عن أخطاء الذاكرة (docs.n8n.io/hosting/scaling/memory-errors) يفصّل قيم --max-old-space-size الموصى بها حسب الذاكرة المتاحة ويسرد معاملات التوسع. مشكلة GitHub n8n-io/n8n#17461 (OOM في الإنتاج، فُتحت مارس 2026، 80+ تعليق) توثق حالات حقيقية — بما في ذلك الارتباط بين سير عمل معالجة CSV وعطل heap — والإعدادات التي استقرت بها خوادم مشابهة لخادمك.
إن كنت تدير عدة نسخ من n8n لعملاء مختلفين، فصل main/worker المشروح هنا هو أيضاً أساس بنية متعددة المستأجرين: كل عميل يمكن أن يملك مجموعة عمال خاصة بحد V8 مستقل، دون أن يؤثر سير عمل ثقيل لحساب على حسابات أخرى.