Microservicios en Rust: arquitectura y práctica para principiantes

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: ¿Por qué Rust para microservicios?

La arquitectura de microservicios se ha convertido desde hace tiempo en el estándar para construir sistemas distribuidos escalables. Normalmente, para su implementación se elige Go, Java o Node.js. Sin embargo, en los últimos años, Rust está atrayendo cada vez más atención: un lenguaje de programación de sistemas que combina el rendimiento de C++ con la seguridad de la memoria. En este artículo en pythonlib.ru, analizaremos cómo crear microservicios en Rust, qué bibliotecas usar y cómo organizar la arquitectura.

Rust es ideal para microservicios gracias a:

  • Ausencia de recolector de basura (baja latencia y consumo de memoria predecible);
  • Trabajo seguro con la memoria en tiempo de compilación;
  • Excelente soporte para asincronía a través del ecosistema Tokio;
  • Pequeño tamaño del archivo binario final (ideal para contenerización).


Arquitectura de un microservicio en Rust

Un microservicio típico en Rust consta de varias capas:

  • Servidor HTTP (generalmente basado en actix-web o axum);
  • Lógica de negocio (funciones puras de Rust);
  • Capa de datos (trabajo con BD mediante sqlx o diesel);
  • Runtime asíncrono (Tokio);
  • Serialización (principalmente serde para JSON).

Veamos la arquitectura básica con el ejemplo de un servicio simple de gestión de usuarios.



1. Configuración del proyecto y dependencias

Cree un nuevo proyecto Cargo y agregue las dependencias en 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. Creación de la estructura básica del servidor

Definamos los modelos de datos e iniciemos el servidor HTTP:

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

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

// Almacenamiento en memoria para el ejemploasync 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!("Iniciando user-service en 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}

Este es un microservicio mínimo. Tenga en cuenta: #[actix_web::main] es una macro que inicia el runtime asíncrono Tokio.



3. Trabajo asíncrono con la base de datos

Un microservicio real debe persistir datos. Usamos sqlx para PostgreSQL. Creemos un archivo .env con la URL de conexión:

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

Ahora escribamos una función para obtener usuarios de la BD:

use sqlx::PgPool;

async fn get_users_from_db(pool: web::Data<PgPool>) -> impl Responder { // Ejecutamos la consulta SQL y mapeamos el resultado a la estructura 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

Blogs

Book Recommendations