وظائف Serverless بلغة Rust: AWS Lambda من الألف إلى الياء

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا تعتبر Rust لـ Serverless نقلة نوعية

\n\n

أصبحت بنية Serverless معيارًا منذ فترة طويلة لبناء تطبيقات قابلة للتوسع واقتصادية. ومع ذلك، فإن اختيار اللغات التقليدية (Python, Node.js, Java) غالبًا ما يواجه مشكلة زمن البدء البارد واستهلاك عالي للذاكرة. تقدم Rust، مع تكلفتها الصفرية للتجريدات وعدم وجود جامع للقمامة، حلاً ثوريًا. في هذه المقالة، سنشرح كيفية إنشاء وتكوين ونشر وظائف serverless بلغة Rust لـ AWS Lambda - بدءًا من تثبيت الأدوات وصولاً إلى إصدارات الإنتاج.

\n\n

بنهاية المقالة، ستكون قادرًا على:

\n
    \n
  • إعداد بيئة تطوير Rust + AWS Lambda
  • \n
  • كتابة وظيفة فعالة مع معالجة الأحداث
  • \n
  • تحسين الملف الثنائي لتقليل زمن البدء البارد
  • \n
  • نشر الوظيفة في AWS باستخدام Cargo Lambda
  • \n
\n\n

تجهيز البيئة: Cargo Lambda و AWS CLI

\n\n

للعمل مع Rust على AWS Lambda، نحتاج إلى أداة خاصة - cargo-lambda. تقوم بأتمتة البناء والاختبار والنشر. سنقوم بتثبيتها عبر Cargo:

\n\n
cargo install cargo-lambda
\n\n

تأكد أيضًا من تثبيت aws-cli (مُهيأ بمفاتيح IAM) و Docker (للاختبار المحلي). لننشئ مشروعًا جديدًا:

\n\n
cargo lambda new my-rust-lambda\ncd my-rust-lambda
\n\n

سينشئ الأمر هيكلًا أساسيًا مع ملف Cargo.toml و src/main.rs. لاحظ التبعيات في Cargo.toml:

\n\n
[package]\nname = "my-rust-lambda"\nversion = "0.1.0"\nedition = "2021"\n\n[dependencies]\nlambda_runtime = "0.11"\ntokio = { version = "1", features = ["macros", "rt-multi-thread"] }\nserde = { version = "1.0", features = ["derive"] }\nserde_json = "1.0"\ntracing = { version = "0.1", features = ["log"] }\ntracing-subscriber = { version = "0.3", features = ["fmt"] }
\n\n

المكتبة الأساسية هي lambda_runtime. توفر trait LambdaHandler الذي سنقوم بتطبيقه.

\n\n

كتابة أول وظيفة: معالجة طلب API Gateway

\n\n

لننظر في سيناريو كلاسيكي: وظيفة تستقبل JSON باسم المستخدم وتعيد تحية. افتح src/main.rs واكتب الكود التالي:

\n\n
use lambda_runtime::{run, service_fn, Error, LambdaEvent};\nuse serde::{Deserialize, Serialize};\n\n#[derive(Deserialize)]\nstruct Request {\n    name: String,\n}\n\n#[derive(Serialize)]\nstruct Response {\n    message: String,\n}\n\nasync fn function_handler(event: LambdaEvent<Request>) -> Result<Response, Error> {\n    let name = event.payload.name;\n    let message = format!("مرحبًا، {}! لقد قمت للتو بتشغيل Rust على Lambda!", name);\n    Ok(Response { message })\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Error> {\n    tracing_subscriber::fmt()\n        .with_max_level(tracing::Level::INFO)\n        .init();\n\n    run(service_fn(function_handler)).await\n}
\n\n

دعنا نحلل النقاط الرئيسية:

\n
    \n
  • LambdaEvent<Request> - هيكل يحتوي على نص الطلب وسياق التنفيذ.
  • \n
  • #[tokio::main] - وقت تشغيل غير متزامن ضروري لعمل Lambda runtime.
  • \n
  • serde - إلغاء تسلسل JSON الوارد وتسلسل الاستجابة.
  • \n
\n\n

اختبر محليًا:

\n\n
cargo lambda watch
\n\n

ثم في محطة طرفية أخرى:

\n\n
cargo lambda invoke --data-ascii '{"name": "أليكسي"}'
\n\n

يجب أن ترى: {"message":"مرحبًا، أليكسي! لقد قمت للتو بتشغيل Rust على Lambda!"}

\n\n

تحسين زمن البدء البارد وحجم الملف الثنائي

\n\n

الميزة الرئيسية لـ Rust هي الحد الأدنى من زمن البدء البارد. ومع ذلك، لتحقيق ذلك، تحتاج إلى بناء الملف الثنائي بشكل صحيح

المدونات

توصيات الكتب