Кэширование в Rust: Redis, Memcached и встроенные решения от А до Я

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

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

Начать курс

Введение в кэширование в Rust

Кэширование — один из ключевых инструментов для повышения производительности приложений на Rust. Независимо от того, создаёте ли вы высоконагруженный веб-сервер, базу данных или десктопное приложение, грамотное кэширование позволяет сократить время ответа, снизить нагрузку на внешние ресурсы и оптимизировать использование памяти. В этой статье мы разберём три основных подхода к кэшированию в экосистеме Rust: использование внешних систем (Redis и Memcached) и встроенные решения, такие как lru-rs и moka. Вы узнаете, когда какой инструмент выбрать, и получите готовые примеры кода.

Внешние системы кэширования: Redis и Memcached

Кэширование с Redis в Rust

Redis — это популярное in-memory хранилище данных, поддерживающее различные структуры данных (строки, списки, множества, хеш-таблицы). Для работы с Redis в Rust используется крейт redis (или redis-rs).

Установим зависимость в Cargo.toml:

[dependencies]
redis = { version = "0.25", features = ["tokio-comp"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"

Пример подключения и базового кэширования с Redis:

use redis::AsyncCommands;
use serde::{Serialize, Deserialize};

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

#[tokio::main]
async fn main() -> redis::RedisResult<()> {
    let client = redis::Client::open("redis://127.0.0.1:6379/")?;
    let mut conn = client.get_multiplexed_async_connection().await?;

    // Сохраняем объект в кэш (сериализуем в JSON)
    let user = User {
        id: 1,
        name: "Алексей".into(),
        email: "alex@example.com".into(),
    };
    let json = serde_json::to_string(&user).unwrap();
    conn.set_ex("user:1", json, 3600).await?; // TTL = 1 час

    // Читаем из кэша
    let cached: String = conn.get("user:1").await?;
    let user_cached: User = serde_json::from_str(&cached).unwrap();
    println!("Получен пользователь: {:?}", user_cached);

    Ok(())
}

Плюсы Redis: поддержка сложных структур данных, TTL, pub/sub, репликация, кластеризация. Минусы: требует отдельного сервера, сетевые задержки.

Кэширование с Memcached в Rust

Memcached — более лёгкое и простое in-memory хранилище, ориентированное на хранение пар "ключ-значение". Для Rust используется крейт memcache.

Добавим в Cargo.toml:

[dependencies]
memcache = "0.19"
tokio = { version = "1", features = ["full"] }

Пример работы с Memcached:

use memcache::Client;

#[tokio::main]
async fn main() -> memcache::MemcacheResult<()> {
    let client = Client::connect("memcache://127.0.0.1:11211")?;

    // Запись с TTL (в секундах)
    client.set("greeting", "Привет, мир!", 300)?;

    // Чтение
    let value: Option<String> = client.get("greeting")?;
    if let Some(msg) = value {
        println!("Из кэша: {}", msg);
    }

    // Инкремент счётчика
    client.set("counter", "10", 0)?;
    client.increment("counter", 5)?;
    let counter: Option<u64> = client.get("counter")?;
    println!("Счётчик: {:?}", counter);

    Ok(())
}

Плюсы Memcached: простота, высокая скорость, минимальное потребление памяти. Минусы: нет сложных структур данных, только хранение строк/байтов.

Встроенные решения для кэширования в Rust

Библиотека lru-rs (LRU-кэш)

Крейт lru реализует классический алгоритм вытеснения Least Recently Used (LRU). Идеально подходит для кэширования в памяти одного процесса без внешних зависимостей.

[dependencies]
lru = "0.12"
use lru::LruCache;
use std::num::NonZeroUsize;

fn main() {
    // Создаём кэш на 100 элементов
    let mut cache: LruCache<String, Vec<u8>> = 
        LruCache::new(NonZeroUsize::new(100).unwrap());

    // Добавляем данные
    cache.put("key1".to_string(), vec![1, 2, 3]);
    cache.put("key2".to_string(), vec![4, 5, 6]);

    // Читаем (обновляет порядок LRU)
    if let Some(data) = cache.get(&"key1".to_string()) {
        println!("Данные: {:?}", data);
    }

    // Принудительное удаление
    cache.pop(&"key2".to_string());

    println!("Размер кэша: {}", cache.len()); // 1
}

Когда использовать: однопоточные приложения, небольшие объёмы данных, простая логика вытеснения.

Библиотека moka (высокопроизводительный конкуретный кэш)

moka — это современная, высокопроизводительная библиотека для кэширования с поддержкой конкурентного доступа, TTL и различных политик вытеснения (LRU, LFU, TinyLFU). Рекомендуется для многопоточных приложений.

[dependencies]
moka = { version = "0.12", features = ["future"] }
tokio = { version = "1", features = ["full"] }
use moka::future::Cache;

#[tokio::main]
async fn main() {
    // Создаём кэш с максимальным размером 10 000 элементов
    let cache: Cache<String, String> = Cache::builder()
        .max_capacity(10_000)
        .time_to_live(std::time::Duration::from_secs(3600)) // TTL 1 час
        .build();

    // Вставляем                

Блоги

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