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

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

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

Начать курс

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

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

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

redis-rs — основной и наиболее зрелый клиент для Redis на Rust. Он поддерживает все основные возможности: строки, списки, хэши, pub/sub, транзакции и кластеризацию.

Установка

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

Пример: базовое кэширование с Redis

use redis::{AsyncCommands, Client};
use std::time::Duration;

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

    // Устанавливаем ключ с TTL 60 секунд
    con.set_ex("user:1:profile", "{\"name\":\"Alice\"}", 60).await?;

    // Читаем значение
    let data: Option<String> = con.get("user:1:profile").await?;
    println!("Получено: {:?}", data);

    // Инкремент счётчика
    let count: i64 = con.incr("page_views", 1).await?;
    println!("Просмотров страницы: {}", count);

    Ok(())
}

Важные особенности:

  • Асинхронность: redis-rs поддерживает как синхронный, так и асинхронный (tokio/async-std) режимы.
  • Pipeline: группировка команд для снижения latency.
  • Кластеризация: поддержка Redis Cluster через redis::cluster.

2. Memcached через крейт memcached-rs

Memcached — легковесное распределённое хранилище типа «ключ-значение». Для Rust существует крейт memcached-rs (или memcache).

Пример использования

use memcache::Client;

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

    // Запись с TTL
    client.set("session:token_abc", "user_data", 30)?;

    // Чтение
    let value: Option<String> = client.get("session:token_abc")?;
    println!("Из Memcached: {:?}", value);

    // Удаление
    client.delete("session:token_abc")?;

    Ok(())
}

Когда выбирать Memcached вместо Redis:

  • Если нужно только простое кэширование (ключ-значение).
  • Если важна минимальная задержка (Memcached быстрее Redis для простых операций).
  • Если не нужны структуры данных Redis (списки, хэши, set).

3. Встроенные in-memory кэши: moka и cached

Для кэширования внутри одного процесса (без внешнего сервера) отлично подходят крейты moka и cached.

3.1 Moka — высокопроизводительный кэш

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

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

#[tokio::main]
async fn main() {
    let cache: Cache<String, String> = Cache::builder()
        .max_capacity(10_000)          // максимум 10 000 записей
        .time_to_live(Duration::from_secs(300)) // TTL 5 минут
        .build();

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

    // Получение
    if let Some(value) = cache.get(&"key1".to_string()).await {
        println!("Найдено: {}", value);
    }

    // Попытка получить с вычислением, если нет в кэше
    let value = cache
        .try_get_with("key2".to_string(), async {
            Ok::<String, String>("computed_value".to_string())                    

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