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

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

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

Начать курс

Кэширование в Rust: Redis и другие эффективные решения

В современной высоконагруженной разработке на Rust кэширование играет ключевую роль. Оно позволяет снизить нагрузку на базы данных, ускорить ответы API и оптимизировать работу с дорогостоящими вычислениями. В этой статье мы рассмотрим основные библиотеки для кэширования в экосистеме Rust: от мощного Redis до легковесных in-memory решений.

1. Redis через крейт redis-rs

redis-rs — это основная и наиболее зрелая библиотека для работы с Redis в Rust. Она поддерживает асинхронные операции (через tokio или async-std), кластеризацию, pub/sub и все популярные типы данных Redis.

Установка

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

Базовый пример: кэширование строк

use redis::AsyncCommands;

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

    // Устанавливаем кэш с TTL 60 секунд
    let _: () = con.set_ex("user:123", "{\"name\":\"Alice\"}", 60).await?;

    // Получаем значение
    let cached: String = con.get("user:123").await?;
    println!("Кэшированные данные: {}", cached);

    // Проверяем существование ключа
    let exists: bool = con.exists("user:123").await?;
    println!("Ключ существует: {}", exists);

    Ok(())
}

Сериализация сложных структур

Для кэширования структур данных используйте serde в паре с redis:

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

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

async fn cache_user(con: &mut redis::aio::MultiplexedConnection, user: &User) {
    let json = serde_json::to_string(user).unwrap();
    let _: () = con.set_ex(format!("user:{}", user.id), json, 300).await.unwrap();
}

async fn get_cached_user(con: &mut redis::aio::MultiplexedConnection, id: u32) -> Option<User> {
    let json: Option<String> = con.get(format!("user:{}", id)).await.unwrap();
    json.and_then(|data| serde_json::from_str(&data).ok())
}

2. In-memory кэширование: крейт moka

Moka — это высокопроизводительная библиотека для кэширования в памяти, вдохновленная Caffeine (Java). Она идеально подходит для сценариев, где не требуется внешний сервер, а нужна максимальная скорость.

Особенности moka:

  • Автоматическая эвикция по времени (TTL, TTI) и по размеру
  • Асинхронная синхронизация (background refresh)
  • Безопасность для многопоточного использования (Arc + RwLock)
  • Поддержка весовых политик (weighted cache)

Пример: кэш с TTL и ограничением размера

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

fn main() {
    // Создаём кэш на 1000 элементов с TTL 10 минут
    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());
    if let Some(v) = cache.get("key1") {
        println!("Значение: {}", v);
    }
}

Асинхронный вариант (moka::future::Cache)

use moka::future::Cache;

#[tokio::main]
async fn main() {
    let cache: Cache<u64, String> = Cache::new(10_000);

    // Асинхронная вставка
    cache.insert(42, "Hello async".to_string()).await;

    // Асинхронное получение
    if let Some(val) = cache.get(&42).await {
        println!("{}", val);
    }
}

3. Декларативное кэширование: крейт cached

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

Пример: кэширование результата функции

use cached::proc_macro::cached;

#[cached(size = 100, time = 300)]
fn expensive_com                    

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