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

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

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

Начать курс

Кэширование в Rust: Redis и другие инструменты для ускорения приложений

Кэширование — один из ключевых механизмов оптимизации производительности. В Rust, с его акцентом на скорость и безопасность, выбор правильного инструмента для кэширования может дать значительный прирост. В этой статье рассмотрим популярные библиотеки: redis-rs (с пулом соединений), moka (in-memory кеш) и cached (декораторы функций).

1. Redis: внешний кеш через redis-rs и deadpool

Redis — самый распространённый внешний кэш. Для работы с ним в Rust используется крейт redis-rs. Для production-нагрузок рекомендуется подключать пул соединений через deadpool-redis.

Установка

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

Пример: базовая работа с Redis

use redis::AsyncCommands;
use deadpool_redis::{Config, Runtime};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Создаём пул соединений
    let cfg = Config::from_url("redis://127.0.0.1:6379");
    let pool = cfg.create_pool(Some(Runtime::Tokio1))?;

    // Берём соединение из пула
    let mut conn = pool.get().await?;

    // Устанавливаем значение с TTL 60 секунд
    conn.set_ex("user:42", "{\"name\":\"Alice\",\"role\":\"admin\"}", 60).await?;

    // Читаем
    let value: String = conn.get("user:42").await?;
    println!("Получено: {}", value);

    // Удаляем
    conn.del("user:42").await?;

    Ok(())
}

Сериализация структур

use serde::{Serialize, Deserialize};

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

async fn cache_user(conn: &mut redis::aio::Connection, user: &User) -> redis::RedisResult<()> {
    let key = format!("user:{}", user.id);
    let json = serde_json::to_string(user).unwrap();
    conn.set_ex(key, json, 300).await
}

async fn get_cached_user(conn: &mut redis::aio::Connection, id: u64) -> Option<User> {
    let key = format!("user:{}", id);
    let result: Option<String> = conn.get(key).await.ok()?;
    result.and_then(|json| serde_json::from_str(&json).ok())
}

2. Moka: быстрый in-memory кеш

Moka — высокопроизводительный in-memory кеш, вдохновлённый Caffeine (Java). Поддерживает TTL, ограничение размера и асинхронное обновление.

Установка

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

Пример: кеш с ограничением в 1000 элементов и TTL 10 минут

use moka::future::Cache;
use std::time::Duration;

#[tokio::main]
async fn main() {
    let cache: Cache<String, String> = Cache::builder()
        .max_capacity(1000)
        .time_to_live(Duration::from_secs(600))
        .build();

    // Вставка
    cache.insert("key1".to_string(), "value1".to_string()).await;

    // Чтение
    if let Some(v) = cache.get(&"key1".to_string()).await {
        println!("Найдено: {}", v);
    }

    // Удаление
    cache.invalidate(&"key1".to_string()).await;
}

Автообновление по истечении TTL

let cache: Cache<String, String> = Cache::builder()
    .time_to_live(Duration::from_secs(60))
    .time_to_idle(Duration::from_secs(30)) // сброс TTL при чтении
    .build();

3. Cached: декораторы для функций

Крейт cached позволяет кэшировать результаты функций с помощью атрибутов. Поддерживает различные бэкенды, включая Redis и in-memory.

Установка

[dependencies]
cached = { version = "0.53", features = ["async"] }
tokio = { version = "1", features = ["full"] }

Пример: кеширование асинхронной функции

use cached::proc_macro::cached;
use std::time::Duration;

#[cached                    

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