Introdução ao cache em Rust
Cache é uma das ferramentas-chave para melhorar o desempenho de aplicações em Rust. Independentemente de você estar criando um servidor web de alta carga, um banco de dados ou uma aplicação desktop, um cache bem planejado permite reduzir o tempo de resposta, diminuir a carga em recursos externos e otimizar o uso de memória. Neste artigo, abordaremos três abordagens principais para cache no ecossistema Rust: uso de sistemas externos (Redis e Memcached) e soluções embutidas, como lru-rs e moka. Você aprenderá quando escolher cada ferramenta e obterá exemplos de código prontos.
Sistemas de cache externos: Redis e Memcached
Cache com Redis em Rust
Redis é um popular armazenamento de dados in-memory que suporta várias estruturas de dados (strings, listas, conjuntos, tabelas hash). Para trabalhar com Redis em Rust, utiliza-se a crate redis (ou redis-rs).
Vamos instalar a dependência no Cargo.toml:
[dependencies]redis = { version = "0.25", features = ["tokio-comp"] }tokio = { version = "1", features = ["full"] }serde = { version = "1", features = ["derive"] }serde_json = "1"Exemplo de conexão e cache básico com 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?;
// Salva o objeto no cache (serializa em JSON) let user = User { id: 1, name: "Alexei".into(), email: "alex@example.com".into(), }; let json = serde_json::to_string(&user).unwrap(); conn.set_ex("user:1", json, 3600).await?; // TTL = 1 hora
// Lê do cache let cached: String = conn.get("user:1").await?; let user_cached: User = serde_json::from_str(&cached).unwrap(); println!("Usuário obtido: {:?}", user_cached);
Ok(())}Vantagens do Redis: suporte a estruturas de dados complexas, TTL, pub/sub, replicação, clusterização. Desvantagens: requer um servidor separado, latência de rede.
Cache com Memcached em Rust
Memcached é um armazenamento in-memory mais leve e simples, focado em armazenar pares chave-valor. Para Rust, utiliza-se a crate memcache.
Adicione ao Cargo.toml:
[dependencies]memcache = "0.19"tokio = { version = "1", features = ["full"] }Exemplo de trabalho com Memcached:
use memcache::Client;
#[tokio::main]async fn main() -> memcache::MemcacheResult<()> { let client = Client::connect("memcache://127.0.0.1:11211")?;
// Escrita com TTL (em segundos) client.set("greeting", "Olá, mundo!", 300)?;
// Leitura let value: Option<String> = client.get("greeting")?; if let Some(msg) = value { println!("Do cache: {}", msg); }
// Incremento de contador client.set("counter", "10", 0)?; client.increment("counter", 5)?; let counter: Option<u64> = client.get("counter")?; println!("Contador: {:?}", counter);
Ok(())}Vantagens do Memcached: simplicidade, alta velocidade, consumo mínimo de memória. Desvantagens: sem estruturas de dados complexas, apenas armazenamento de strings/bytes.
Soluções embutidas para cache em Rust
Biblioteca lru-rs (Cache LRU)
A crate lru implementa o clássico algoritmo de despejo Least Recently Used (LRU). Ideal para cache em memó