قوائم الانتظار والمهام الخلفية في Rust: كتابة عامل غير متزامن في ساعة
\n\nهل تساءلت يومًا لماذا تتباطأ خدمة الويب الخاصة بك أحيانًا عندما ينقر المستخدم على زر "إرسال"؟ في أغلب الأحيان، يكون السبب هو العمليات الثقيلة التي يتم تنفيذها أثناء معالجة الطلب. إرسال البريد الإلكتروني، إنشاء PDF، معالجة الصور، التكامل مع واجهات برمجة التطبيقات الخارجية - كل هذه يجب أن تعيش حياتها الخاصة، بدلاً من حظر الرد على المستخدم. الحل هو قوائم الانتظار والمهام الخلفية.
\n\nوإذا كنت معتادًا على حل هذه المشكلة في Python باستخدام Celery أو RQ، فستفاجأ في Rust. Rust ليس سريعًا فحسب - بل يوفر تحكمًا فريدًا في الذاكرة والعمليات، مما يسمح بكتابة عمال فائقين الكفاءة يستهلكون الحد الأدنى من الموارد. في هذه المقالة، سنشرح كيفية تنفيذ قوائم الانتظار والمهام الخلفية في Rust باستخدام المكتبات والأساليب الحديثة. ستتعلم كيفية بناء نظام موثوق لمعالجة المهام لن ينهار تحت الضغط.
\n\nلماذا Rust للمهام الخلفية؟ ثلاث مزايا غير واضحة
\n\nقبل الغوص في الكود، دعنا نفهم لماذا نستخدم Rust لقوائم الانتظار عندما تكون هناك حلول Python مجربة.
\n\n- \n
- أداء بدون جامع القمامة (GC). يمكن للعمال في Python أن "يتجمدوا" أثناء توقف جامع القمامة. Rust خالٍ من هذه المشكلة - أنت تتحكم في كل بايت من الذاكرة. هذا أمر بالغ الأهمية للأنظمة عالية التحميل حيث كل ملي ثانية مهمة. \n
- غير متزامن "خارج الصندوق". Rust مع
tokioأوasync-stdيسمح بمعالجة آلاف الاتصالات المتزامنة على خيط واحد. يمكنك تشغيل مئات العمال دون الخوف من تجاوز الذاكرة. \n - الموثوقية. نظام الملكية (ownership) في Rust يضمن عدم حدوث حالة سباق (data race) في العامل الخلفي. يتم معالجة الأخطاء بشكل صريح - لا توجد استثناءات مخفية. \n
الآن بعد أن فهمنا "لماذا"، ننتقل إلى "كيف".
\n\nاختيار وسيط الرسائل: RabbitMQ مقابل Redis مقابل NATS
\n\nقائمة انتظار المهام ليست مجرد قائمة. إنها وسيط رسائل يخزن المهام ويوزعها بين العمال. في نظام Rust البيئي، توجد كريتات (crates) لجميع الوسطاء المشهورين.
\n\nRabbitMQ + lapin: الكلاسيكية في عالم قوائم الانتظار
\n\nRabbitMQ هو وحش موثوق لمهام المؤسسات. توفر كريتة lapin واجهة برمجة تطبيقات غير متزامنة نظيفة. إنها مثالية إذا كنت بحاجة إلى توجيه الرسائل وضمانات التسليم والطوبولوجيات المعقدة.
Redis + fred: البساطة والسرعة
\n\nRedis هو سكين سويسري. باستخدام fred (عميل Redis غير متزامن)، يمكنك إنشاء قائمة انتظار من خلال القوائم (BLPOP) أو Pub/Sub. Redis مناسب تمامًا للسيناريوهات البسيطة: "أرسل مهمة - احصل على نتيجة".
NATS + async-nats: وسيط خفيف الوزن
\n\nNATS هو وسيط سحابي بأقل تأخير. إذا كنت بحاجة إلى معالجة ملايين الرسائل في الثانية على مثيلات صغيرة، فإن NATS هو خيارك.
\n\nفي هذه المقالة، سنركز على RabbitMQ لأنه يوفر التحكم الأكثر شمولاً. لكن المبادئ ستكون نفسها لأي وسيط.
\n\nكتابة قائمة انتظار في Rust: مثال خطوة بخطوة
\n\nلنقم بإنشاء نظام بسيط: مولد المهام (producer) وعامل (consumer). سنقوم بمعالجة مهام إرسال البريد الإلكتروني.
\n\nالخطوة 1: إعداد المشروع والتبعيات
\n\nأنشئ مشروعًا جديدًا:
\n\ncargo new rust_queue_demo\ncd rust_queue_demo\n\nأضف التبعيات إلى Cargo.toml:
[dependencies]\ntokio = { version = "1", features = ["full"] }\nlapin = "2.4"\nserde = { version = "1", features = ["derive"] }\nserde_json = "1"\ntracing = "0.1"\ntracing-subscriber = "0.3"\nanyhow = "1"\n\nنستخدم tokio كبيئة تشغيل غير متزامنة، و lapin لـ RabbitMQ، و serde لتسلسل المهام، و tracing للتسجيل.