ميكروسيرفيسات بلغة Rust: الهندسة المعمارية والتطبيق العملي للمبتدئين

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

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

ابدأ الدورة

مقدمة: لماذا Rust للخدمات المصغرة؟

أصبحت بنية الخدمات المصغرة معياراً لبناء الأنظمة الموزعة القابلة للتوسع منذ فترة طويلة. عادةً ما يتم اختيار Go أو Java أو Node.js لتنفيذها. ومع ذلك، في السنوات الأخيرة، جذبت Rust اهتماماً متزايداً - وهي لغة برمجة أنظمة تجمع بين أداء C++ وأمان الذاكرة. في هذه المقالة على pythonlib.ru، سنشرح كيفية إنشاء الخدمات المصغرة باستخدام Rust، والمكتبات التي يجب استخدامها، وكيفية تنظيم البنية.

تعتبر Rust مثالية للخدمات المصغرة بفضل:

  • عدم وجود جامع للقمامة (زمن وصول منخفض واستهلاك ذاكرة يمكن التنبؤ به)؛
  • العمل الآمن مع الذاكرة في مرحلة التجميع؛
  • الدعم الممتاز للبرمجة غير المتزامنة من خلال نظام Tokio البيئي؛
  • حجم الملف الثنائي النهائي الصغير (مثالي للحاويات).


بنية الخدمة المصغرة باستخدام Rust

تتكون الخدمة المصغرة النموذجية في Rust من عدة طبقات:

  • خادم HTTP (عادةً بناءً على actix-web أو axum)؛
  • منطق الأعمال (دوال Rust نقية)؛
  • طبقة البيانات (التعامل مع قاعدة البيانات عبر sqlx أو diesel)؛
  • بيئة التشغيل غير المتزامنة (Tokio)؛
  • التسلسل (غالباً serde لـ JSON).

دعنا نلقي نظرة على البنية الأساسية باستخدام مثال خدمة إدارة مستخدمين بسيطة.

1. إعداد المشروع والتبعيات

أنشئ مشروع Cargo جديداً وأضف التبعيات في Cargo.toml:

[package]
name = "user-service"
version = "0.1.0"
edition = "2021"

[dependencies]
actix-web = "4"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["full"] }
sqlx = { version = "0.7", features = ["runtime-tokio", "postgres"] }
dotenv = "0.15"

2. إنشاء الهيكل الأساسي للخادم

سنحدد نماذج البيانات ونشغل خادم HTTP:

use actix_web::{web, App, HttpServer, Responder};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Clone)]
struct User {
    id: u32,
    name: String,
    email: String,
}

// مخزن في الذاكرة للمثال
async fn get_users() -> impl Responder {
    let users = vec![
        User { id: 1, name: "Alice".into(), email: "alice@example.com".into() },
        User { id: 2, name: "Bob".into(), email: "bob@example.com".into() },
    ];
    web::Json(users)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    println!("Starting user-service on http://127.0.0.1:8080");

    HttpServer::new(|| {
        App::new()
            .route("/users", web::get().to(get_users))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

هذه خدمة مصغرة بالحد الأدنى. لاحظ: #[actix_web::main] هو ماكرو يقوم بتشغيل بيئة التشغيل غير المتزامنة Tokio.

3. العمل غير المتزامن مع قاعدة البيانات

يجب أن تحفظ الخدمة المصغرة الحقيقية البيانات. سنستخدم sqlx لقاعدة بيانات PostgreSQL. لننشئ ملف .env مع رابط الاتصال:

DATABASE_URL=postgres://user:password@localhost/users_db

الآن سنكتب دالة لجلب المستخدمين من قاعدة البيانات:

use sqlx::PgPool;

async fn get_users_from_db(pool: web::Data<PgPool>) -> impl Responder {
    // تنفيذ استعلام SQL وربط النتيجة بهيكل User
    let users: Vec<User> = sqlx::query_as::<_, User>("SELECT id, name, email FROM users")
        .fetch_all(pool.get_ref())
        .await
        .unwrap_or_default();

    web::Json(users)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    dotenv::dotenv().ok();
    let database_url = std::env::va                

المدونات

توصيات الكتب