Микросервисы на Rust: с чего начать и не сойти с ума

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Почему Rust — это ваш следующий шаг в микросервисах?

Мир микросервисов долгое время был поделен между Java (со своим Spring Boot), Python (FastAPI, Django) и Go. Но последние пару лет всё чаще слышен голос Rust. Почему? Потому что Rust даёт то, что раньше казалось недостижимым: производительность C++ и безопасность памяти — без сборщика мусора.

Если вы пишете на Python, вы привыкли к скорости разработки. Но когда нагрузка растёт, Python начинает «тормозить». Rust решает эту проблему радикально: один микросервис на Rust может заменить 3–4 сервиса на Python по производительности. И при этом код не «сыпется» в рантайме с NullPointerException.

В этой статье мы не будем философствовать. Мы возьмём и напишем микросервис на Rust с нуля. Вы увидите, что это не страшно, а очень даже увлекательно.

Готовим окружение: что нужно установить

Прежде чем писать код, давайте убедимся, что у вас есть всё необходимое. Если вы новичок в Rust — не пугайтесь, установка занимает 2 минуты.

1. Установка Rust

Самый простой способ — через официальный установщик rustup:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

После установки проверьте версию:

rustc --version
cargo --version

2. Выбор редактора

Рекомендую VS Code с расширением rust-analyzer. Это даст вам автодополнение, подсветку ошибок и рефакторинг «из коробки».

3. Docker (для контейнеризации)

Микросервисы обычно живут в контейнерах. Установите Docker Desktop или Docker Engine. Мы будем собирать образ в конце статьи.

Выбираем фреймворк: Actix-web vs Axum vs Rocket

В мире Rust есть три основных фреймворка для HTTP-серверов. Вот их краткое сравнение:

  • Actix-web — самый быстрый (до 1 млн запросов/сек). Зрелый, много примеров. Идеален для продакшена.
  • Axum — современный, от создателей Tokio. Лучше всего интегрируется с async-экосистемой.
  • Rocket — самый «дружелюбный» синтаксис, но медленнее обновляется.

В этой статье мы будем использовать Actix-web, так как он проверен годами и имеет наибольшее комьюнити. Но если вы хотите «модный» стек — смело берите Axum.

Первый микросервис: сервис сокращения ссылок

Чтобы не быть абстрактными, напишем реальный микросервис — url-shortener. Он будет принимать длинный URL и возвращать короткий.

Шаг 1. Создаём проект

cargo new url-shortener
cd url-shortener

Шаг 2. Добавляем зависимости

Откройте Cargo.toml и добавьте:

[dependencies]
actix-web = "4"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
uuid = { version = "1", features = ["v4"] }
tokio = { version = "1", features = ["full"] }

Шаг 3. Пишем код

Замените содержимое src/main.rs на следующий код:

use actix_web::{web, App, HttpServer, HttpResponse, Responder};
use serde::{Deserialize, Serialize};
use std::sync::Mutex;
use uuid::Uuid;

// Структура для хранения ссылок в памяти
struct AppState {
    links: Mutex>,
}

#[derive(Serialize, Deserialize, Clone)]
struct Link {
    id: String,
    url: String,
}

#[derive(Deserialize)]
struct CreateLinkRequest {
    url: String,
}

// POST /shorten — создаёт короткую ссылку
async fn shorten(data: web::Data<AppState>, body: web::Json<CreateLinkRequest>) -> impl Responder {
    let new_link = Link {
        id: Uuid::new_v4().to_string()[..8].to_string(), // берём первые 8 символов UUID
        url: body.url.clone(),
    };

    let mut links = data.links.lock().unwrap();
    links.push(new_link.clone());

    HttpResponse::Created().json(&new_link)
}

// GET /{id} — редирект на оригинальный URL
async fn redirect(data: web::Data<AppState>, path: web::Path<String>) -> impl Responder {
    let id = path.into_inner();
    let links = data.links.lock().unwrap();

    if let Some(link) = links.iter().find(|l| l.id == id) {
        HttpResponse::Found()
            .append_header(("Location", link.url.clone()))
            .finish()
    } else {
        HttpResponse::NotFound().body("Link not found")
    }
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let data = web::Data::new(AppState {
        links: Mutex::new(Vec::new()),
    });

    println!("Server running at http://127.0.0.1:8080");

    HttpServer::new(move || {
        App::new()
            .app_data(data.clone())
            .route("/shorten", web::post().to(shorten))
            .route("/{id}", web::get().to(redirect))
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

Шаг 4. Запускаем и тестируем

cargo run

В другом терминале:

# Создаём короткую ссылку
curl -X POST http://127.0.0.1:8080/shorten -H "Content-Type: application/json" -d '{"url": "https://pythonlib.ru"}'

# Ответ: {"id":"a1b2c3d4","url":"https://pythonlib.ru"}

# Переходим по короткой ссылке
curl -v http://127.0.0.1:8080/a1b2c3d4

Вы увидите редирект (HTTP 302) на сайт pythonlib.ru. Работает! 🎉

Добавляем асинхронность и базу данных

Хранить данные в памяти — это несерьёзно для микросервиса. Давайте подключим PostgreSQL и SQLx (асинхронный драйвер).

Добавляем SQLx в Cargo.toml

sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "postgres", "uuid"] }

Создаём таблицу

CREATE TABLE links (
    id VARCHAR(8) PRIMARY KEY,
    url TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT NOW()
);

Обновляем код для работы с БД



                
                

Блоги

Рекомендаций по книгам