Mikroservices in Rust: Architektur und Praxis für Einsteiger

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Warum Rust für Microservices?

Die Microservice-Architektur ist seit langem der Standard für den Aufbau skalierbarer verteilter Systeme. Üblicherweise werden dafür Go, Java oder Node.js gewählt. In den letzten Jahren zieht jedoch Rust immer mehr Aufmerksamkeit auf sich – eine systemnahe Programmiersprache, die die Leistung von C++ mit Speichersicherheit kombiniert. In diesem Artikel auf pythonlib.ru werden wir untersuchen, wie man Microservices in Rust erstellt, welche Bibliotheken man verwendet und wie man die Architektur organisiert.

Rust eignet sich ideal für Microservices aufgrund von:

  • Keinem Garbage Collector (geringe Latenz und vorhersehbarer Speicherverbrauch);
  • Sicherer Speicherverwaltung zur Kompilierzeit;
  • Hervorragender Unterstützung für Asynchronität durch das Tokio-Ökosystem;
  • Kleiner Größe der resultierenden Binärdatei (ideal für Containerisierung).


Architektur eines Microservices in Rust

Ein typischer Microservice in Rust besteht aus mehreren Schichten:

  • HTTP-Server (normalerweise basierend auf actix-web oder axum);
  • Geschäftslogik (reine Rust-Funktionen);
  • Datenschicht (Datenbankzugriff über sqlx oder diesel);
  • Asynchroner Runtime (Tokio);
  • Serialisierung (meistens serde für JSON).

Betrachten wir die grundlegende Architektur am Beispiel eines einfachen Benutzerverwaltungsdienstes.



1. Projekteinrichtung und Abhängigkeiten

Erstellen Sie ein neues Cargo-Projekt und fügen Sie die Abhängigkeiten in Cargo.toml hinzu:

[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. Erstellung der grundlegenden Serverstruktur

Definieren wir die Datenmodelle und starten den HTTP-Server:

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

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

// In-Memory-Speicher für das Beispielasync 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}

Dies ist ein minimaler Microservice. Beachten Sie: #[actix_web::main] ist ein Makro, das die asynchrone Runtime Tokio startet.



3. Asynchrone Datenbankarbeit

Ein echter Microservice sollte Daten speichern. Wir verwenden sqlx für PostgreSQL. Erstellen Sie eine .env-Datei mit der Verbindungs-URL:

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

Jetzt schreiben wir eine Funktion zum Abrufen von Benutzern aus der Datenbank:

use sqlx::PgPool;

async fn get_users_from_db(pool: web::Data<PgPool>) -> impl Responder { // SQL-Abfrage ausführen und Ergebnis in die User-Struktur mappen 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

Blogs

Buchempfehlungen