Кэширование в 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())