UGLYPEAR AI تُكمل ترقية أعمالها: ضغط المستندات عالي الأداء × أساس هندسة بيانات RAGتعرّف على الأعمال الجديدة →

تصميم قائمة انتظار مهام الضغط: المعالجة غير المتزامنة عبر Celery+Redis

خلاصة سريعة: الحل القياسي لجعل مهام الضغط غير متزامنة هو قائمة انتظار المهام Celery + Redis، والبنية الأساسية هي: Producer (FastAPI لإرسال المهام) ← Broker (Redis للتخزين المؤقت) ← Worker (Celery للاستهلاك واستدعاء محرك ضغط Rust) ← Backend (Redis لتخزين النتائج). عند معالجة 10000 ملف دفعة واحدة، بتقسيم كل دفعة إلى 100 ملف و12 عامل Worker متزامن، يمكن إكمال كل شيء في نحو 40 دقيقة. نقاط التصميم الرئيسية هي تقسيم المهام، قوائم الانتظار ذات الأولوية، إعادة المحاولة مع التراجع الأسي، وقائمة الانتظار المهمّة (DLQ) كحل أخير. سنبدأ ببنية قائمة الانتظار، ثم نقدم جدول معاملات تهيئة Celery وخطة تنفيذ كاملة.

إذا لم تكن على دراية بالنشر الشامل لخدمة الضغط، يُنصح بقراءة الدليل الكامل لنشر خدمة الضغط عبر Docker.

أولًا: لماذا تحتاج مهام الضغط إلى قائمة انتظار غير متزامنة

يُعدّ ضغط الملفات مهمة نموذجية كثيفة الاستخدام للمعالج وكثيفة الإدخال/الإخراج في آن واحد. قد يستغرق ضغط ملف PDF بحجم 100 ميجابايت من 5 إلى 15 ثانية، وعند معالجته عبر واجهة متزامنة يظل اتصال HTTP معلقًا لفترة طويلة، وتكون قدرة التزامن على جهاز واحد ضعيفة للغاية. تفصل قائمة الانتظار غير المتزامنة بين «الإرسال» و«التنفيذ»: يحصل العميل فورًا على task_id بعد إرسال المهمة، ويضغطها الـ Worker في الخلفية ببطء، ثم تُعاد النتيجة عبر الاستدعاء أو الاستعلام الدوري بعد الاكتمال.

طريقة المعالجةقدرة التزامنزمن الاستجابةمعالجة الفشلالحجم المناسب
المعالجة المتزامنةضعيفة (تحجب اتصال HTTP)5–60 ثانيةبدون إعادة محاولة، خطأ مباشرأقل من 10 ملفات
تجمع الخيوطمتوسطة (محدودة بعدد الخيوط)1–5 ثوانٍتحتاج تنفيذ يدوي10–100 ملف
قائمة Celery غير المتزامنةعالية (توسعة أفقية للـ Worker)أقل من 200 مللي ثانيةإعادة محاولة تلقائية + قائمة DLQ100–100000 ملف
Kubernetes + قائمة انتظارعالية جدًا (توسعة مرنة HPA)أقل من 100 مللي ثانيةنظام تحمّل أخطاء كاملأكثر من 100000 ملف

تعتمد الإصدارة الشبكية من SmartSlim لـ UGLYPEAR DATA بنية FastAPI + Celery + Redis + MinIO، وتعمل بشكل مستقر بـ 12 مهمة متزامنة على جهاز واحد، وعند نشرها على Kubernetes يمكن لـ HPA التوسع والانكماش تلقائيًا بين 3 و10 نسخ. تدعم هذه البنية بالفعل احتياجات الضغط اليومية بعشرات الآلاف من الملفات لعملاء من المؤسسات.

ثانيًا: شرح مفصّل لبنية قائمة انتظار Celery

تتكون قائمة انتظار المهام Celery من أربعة أدوار أساسية: Producer (المنتج)، Broker (وكيل الرسائل)، Worker (عملية العمل)، Backend (تخزين النتائج). إن فهم مسؤوليات هذه الطبقات الأربع هو الأساس لتهيئة قائمة انتظار مهام الضغط بشكل صحيح.

المكوّنالخيار التقنيالمسؤوليةالإعداد الرئيسي
ProducerFastAPIاستقبال طلبات HTTP، إنشاء المهام، إرسالها إلى Brokertask.apply_async(queue=...)
BrokerRedis 7.xتخزين رسائل المهام المعلّقة مؤقتًا، يدعم قوائم الأولويةbroker_url, visibility_timeout
WorkerCelery 5.xاستهلاك المهام، استدعاء محرك ضغط Rust لتنفيذ الضغطconcurrency, prefork pool
BackendRedisتخزين حالة المهام والنتائج المُعادةresult_backend, result_expires
طبقة التخزينMinIOتخزين الملفات الأصلية والملفات المضغوطةبروتوكول متوافق مع S3، رفع مجزأ

1. جدول معاملات تهيئة Celery الأساسية

تحدد إعدادات Celery بشكل مباشر قدرة واستقرار قائمة الانتظار. يعرض الجدول التالي الإعدادات الموصى بها لسيناريو الضغط، وقد تم التحقق منها في بيئة الإنتاج لـ SmartSlim.

المعاملالقيمة الموصى بهاالوصف
broker_urlredis://:password@redis:6379/0Redis كوكيل رسائل، استخدام قاعدة بيانات مستقلة لتجنب التعارضات
result_backendredis://:password@redis:6379/1تخزين النتائج في قاعدة بيانات مستقلة، معزولة عن Broker
task_serializerjsonتسلسل JSON، متوافق عبر اللغات
result_serializerjsonالنتائج تستخدم JSON أيضًا
accept_content['json']قبول JSON فقط، تعزيز الأمان
timezoneAsia/Shanghaiتوحيد المنطقة الزمنية
task_acks_lateTrueإرسال ACK بعد اكتمال المهمة، حتى لا تضيع المهمة عند الانهيار
worker_prefetch_multiplier1كل Worker يجلب مهمة واحدة فقط مسبقًا، لتجنب تجويع المهام الطويلة
task_time_limit600مهلة صلبة 600 ثانية للمهمة الواحدة
task_soft_time_limit540مهلة لينة 540 ثانية، تُفعّل SoftTimeLimitExceeded
task_reject_on_worker_lostTrueرفض المهمة عند خروج Worker بشكل غير طبيعي، وإعادة إدخالها في القائمة
result_expires86400تنظيف النتائج تلقائيًا بعد 24 ساعة

2. تصميم قائمة الانتظار حسب الأولوية

تتفاوت مهام الضغط في أولويتها: طلبات الضغط في الوقت الحقيقي من المستخدم تتطلب استجابة سريعة، أما مهام الأرشفة المجدولة فيمكن تشغيلها ببطء. تُنفَّذ جدولة تفاضلية عبر قائمة الأولوية في Redis، حيث تُستهلَك المهام ذات الأولوية العالية من قِبل Worker أولًا.

اسم قائمة الانتظارالأولويةقاعدة التوجيهالمهام النمطية
compression_high9 (الأعلى)طلبات المستخدم في الوقت الحقيقيضغط فوري لملف واحد
compression_normal5 (افتراضي)المهام الدفعيةضغط دفعي من 100 إلى 500 ملف
compression_low1 (الأدنى)أرشفة مجدولةأرشفة كاملة ليلية
dlq_queue— (قائمة مهمّة)المهام التي فشلت إعادة المحاولة فيهامعالجة يدوية أو تعويضية

ثالثًا: حالة عملية: ضغط غير متزامن لـ 10000 ملف

هذه حالة أرشفة بيانات لمؤسسة ما: 10000 وثيقة تاريخية (مزيج من PDF وWord والصور، متوسط حجم الملف 8 ميجابايت، بإجمالي نحو 80 جيجابايت) تحتاج إلى ضغط وأرشفة موحَّدين. المتطلب: الاكتمال خلال ساعة واحدة، ونسبة ضغط لا تقل عن 60%.

تصميم الحل: تقسيم 100 ملف لكل دفعة إلى 100 مهمة فرعية، والإرسال بالدفعات عبر مجموعة Celery group، مع استهلاك 12 Worker بشكل متزامن. تستدعي كل مهمة فرعية محرك ضغط Rust بشكل تسلسلي لضغط 100 ملف.

معاملات التنفيذ وأداء الإنتاجية:

المؤشرالمعاملالقيمة المقاسةالوصف
إجمالي عدد الملفات10000 ملفصيغ مختلطة، متوسط 8 ميجابايت/الملف
دقة التقسيم100 ملف/دفعة100 مهمة فرعيةموازنة بين تكلفة الجدولة وتكلفة إعادة المحاولة
تزامن الـ Worker12وضع preforkمعالج أحادي بـ 12 نواة
زمن ضغط الملف الواحدمتوسط 3.2 ثانيةمحرك Rust بمستوى medium
زمن الدفعة الواحدةنحو 5.3 دقيقة100 ملف بشكل تسلسلي
الزمن الإجمالينحو 44 دقيقة100 دفعة / 12 تزامن
نسبة الضغط67.3%80 جيجابايت ← 26.2 جيجابايت
عدد حالات الفشل17 ملفًاملفات تالفة، إلى قائمة DLQ بعد إعادة المحاولة

النتيجة: إكمال ضغط 10000 ملف في 44 دقيقة بنسبة ضغط 67.3%، وانتقال 17 ملفًا تالفًا تلقائيًا إلى قائمة DLQ للمعالجة اليدوية. البنية الكلية مستقرة، وبلغت ذروة استخدام المعالج 89%، وبلغ استهلاك الذاكرة 4.2 جيجابايت، دون أي OOM أو فقدان للمهام.

3. استراتيجية إعادة المحاولة وقائمة الانتظار المهمّة

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

نوع الخطأالاستثناء النمطياستراتيجية المعالجةعدد مرات إعادة المحاولةالمصير النهائي
مؤقت - IOConnectionError, TimeoutErrorإعادة المحاولة بتراجع أسي3 مراتنجاح أو DLQ
مؤقت - مواردMemoryError, OOMKilledتمديد التراجع + تخفيض المستوىمرتاننجاح أو DLQ
حتمي - ملفFileCorrupted, ParseErrorدون إعادة محاولة، مباشرة إلى DLQ0dlq_queue
حتمي - صيغةUnsupportedFormatدون إعادة محاولة، مباشرة إلى DLQ0dlq_queue
حتمي - أذوناتPermissionDeniedدون إعادة محاولة، تنبيه0dlq_queue + تنبيه

تستخدم إعدادات إعادة المحاولة معاملَي autoretry_for وretry_backoff في Celery، مع تراجع ابتدائي قدره 60 ثانية وأقصى 600 ثانية، إضافة إلى ارتجاع عشوائي لتجنب الانهيار الجماعي. تُفحَص المهام في قائمة DLQ دوريًا عبر مهمة مراقبة مستقلة، تُفعِّل تنبيهات WeChat للأعمال أو DingTalk لإعلام عمليات التشغيل بالمعالجة.

مؤشر المراقبةطريقة الجمعحد التنبيهإجراء المعالجة
حجم تراكم قائمة الانتظارRedis LLEN>500تفعيل توسيع Worker
معدل فشل المهامأحداث Celery>5%فحص السجلات + إيقاف الإرسال
طول قائمة DLQRedis LLEN dlq>10تنبيه WeChat للأعمال
عدد الـ Worker النشطةCelery inspect<10إعادة تشغيل Worker تلقائيًا
متوسط زمن المهمةمراقبة Flower>30 ثانيةفحص الملفات الكبيرة + تخفيض المستوى
استخدام المعالجnode_exporter>95%تحديد المعدل + التوسيع

بخصوص طريقة الاستدعاء الكاملة لواجهة برمجة الضغط، يمكنك الرجوع إلى دليل استدعاء واجهة برمجة الضغط: تصميم واجهة REST.

رابعًا: توصيات تهيئة قائمة الانتظار حسب السيناريو

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

السيناريوعدد Workersدقة التقسيمقائمة الأولويةاستراتيجية إعادة المحاولة
ضغط فردي فوري2بدون تقسيمhighإعادة محاولة سريعة 3 مرات
أرشفة مؤسسية دفعية12100 ملف/دفعةnormal/lowتراجع أسي 3 مرات
معالجة حكومية سرية450 ملف/دفعةhighإعادة محاولة صارمة + تدقيق
صور منصات التجارة الإلكترونية16200 ملف/دفعةnormalإعادة محاولة سريعة مرتين
أرشفة ليلية مجدولة8500 ملف/دفعةlowتراجع بطيء 5 مرات
تحويل فيديو في الوقت الحقيقي24ملف واحدhighدون إعادة محاولة، تنبيه عند الفشل

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

خامسًا: الأسئلة الشائعة FAQ

س1: كيف تنفّذ مهام ضغط Celery المعالجة غير المتزامنة؟

أنشئ قائمة انتظار مهام غير متزامنة عبر Celery + Redis: يستقبل FastAPI الطلب ثم يُرسل المهمة إلى Redis Broker، ويستهلك Celery Worker المهمة من Broker ويستدعي محرك ضغط Rust لتنفيذ الضغط، وتُكتب النتائج في Backend وتُخزَّن في MinIO. يكفي استدعاء task.apply_async لتنفيذ المهمة بشكل غير متزامن، والاستعلام عن الحالة عبر task.id. مع 12 Worker متزامن على جهاز واحد، يمكن إكمال 10000 ملف في 100 دفعة خلال 40 دقيقة.

س2: كيف تُعيد مهام الضغط الفاشلة المحاولة تلقائيًا؟

اضبط إعادة المحاولة التلقائية عبر معامل autoretry_for في Celery، مع max_retries=3، وretry_backoff=True (تراجع أسي، ابتدائي 60 ثانية)، وretry_backoff_max=600 ثانية، وretry_jitter=True (ارتجاع عشوائي لتجنب الانهيار الجماعي). تُرسَل المهام التي تفشل بعد 3 محاولات تلقائيًا إلى قائمة DLQ dlq_queue للمعالجة اليدوية أو التعويضية. يُنصح بإعادة المحاولة للأخطاء المؤقتة (انتهاء مهلة IO/نقص الذاكرة)، أما الأخطاء الحتمية (ملف تالف/صيغة غير مدعومة) فإلى DLQ مباشرة.

س3: كيف تُقسَّم 10000 ملف دفعيًا للضغط؟

قسّم إلى 100 ملف لكل دفعة بإجمالي 100 مهمة فرعية. أرسل بالدفعات عبر Celery group أو chord، واستهلك بالتوازي عبر 12 Worker، وكل مهمة فرعية تضغط 100 ملف تسلسليًا. متوسط زمن ضغط الملف 3 ثوانٍ، ووقت الدفعة نحو 5 دقائق، وبعد تشغيل 100 دفعة بالتوازي يكتمل الإجمالي في نحو 40 دقيقة. التقسيم الصغير جدًا (مثل 1 لكل دفعة) يرفع تكلفة الجدولة، والتقسيم الكبير جدًا (مثل 1000 لكل دفعة) يرفع تكلفة إعادة المحاولة عند الفشل، و100 هي القيمة المثلى تجريبيًا.

س4: أيهما أنسب لقائمة انتظار مهام الضغط: Celery أم RQ؟

يُنصح بـ Celery لمهام الضغط. يدعم Celery تقسيم المهام (group/chord)، وقوائم الأولوية، والمهام المجدولة، وسلاسل المهام، وقوائم DLQ، بمجموعة ميزات متكاملة؛ أما RQ فأخفّ لكنه يفتقر إلى التقسيم والأولوية. يدعم Celery بشكل أصلي احتياجات سيناريو الضغط الشائعة: التقسيم الدفعي، الجدولة حسب الأولوية، إعادة المحاولة عند الفشل. من حيث الأداء يعتمد كلاهما على Redis، والإنتاجية متقاربة. تعتمد الإصدارة الشبكية من SmartSlim لـ UGLYPEAR DATA بنية FastAPI + Celery + Redis + MinIO، وتعمل بشكل مستقر بـ 12 تزامن على جهاز واحد.

الخلاصة

الحل القياسي لجعل مهام الضغط غير متزامنة هو قائمة انتظار Celery + Redis، وجوهرها يكمن في الفصل بين الطبقات الأربع Producer/Broker/Worker/Backend. عند مواجهة دفعات بعشرات الآلاف من الملفات، يكفي تقسيمها إلى 100 ملف لكل دفعة و12 Worker متزامن لإكمالها في نحو 40 دقيقة بنسبة ضغط 60%–70%. يجب أن تميّز استراتيجية إعادة المحاولة بين الأخطاء المؤقتة (إعادة المحاولة بتراجع أسي) والأخطاء الحتمية (مباشرة إلى DLQ)، مدعومة بستة مؤشرات مراقبة لضمان استقرار قائمة الانتظار.

احفظ ثلاث نقاط: أولًا، task_acks_late=True يضمن عدم فقدان المهام عند الانهيار؛ ثانيًا، worker_prefetch_multiplier=1 يتجنب تجويع المهام الطويلة؛ ثالثًا، يجب ربط قائمة DLQ بمراقبة وتنبيهات. اختيار بنية قائمة الانتظار الصحيحة واستراتيجية التقسيم الملائمة يرفع إنتاجية واستقرار خدمة الضغط إلى مستوى جديد.

هل تحتاج إلى ضغط الملفات؟ جرّب SmartSlim من UGLYPEAR DATA

مبني على محرك ضغط Rust ذاتي التطوير، يدعم 10 فئات رئيسية بأكثر من 40 صيغة تشمل PDF والصور والفيديو وOffice وOFD، مع ضغط محلي لا تغادر فيه البيانات نطاقك.