Cache em Rust: Redis, Memcached e soluções embutidas

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: Por que cache em Rust?

\n

Velocidade é a principal vantagem do Rust. Mas mesmo o código mais rápido pode esbarrar em entrada/saída (E/S) lenta: consultas a banco de dados, APIs externas ou cálculos de dados complexos. O cache resolve esse problema, armazenando resultados de operações caras em um armazenamento rápido. O Rust oferece ferramentas flexíveis para cache: desde estruturas de dados embutidas simples até poderosos sistemas distribuídos, como Redis e Memcached.

\n

Neste artigo, abordaremos todos os níveis de cache em Rust: desde um simples HashMap até soluções profissionais com TTL (tempo de vida) e sincronização. Você aprenderá como escolher a ferramenta adequada para seu projeto e evitar erros comuns.

\n\n

1. Cache embutido: HashMap e suas variações

\n

A maneira mais simples de fazer cache em Rust é usar HashMap da biblioteca padrão. No entanto, em ambientes multithread, são necessários mecanismos adicionais de sincronização.

\n\n

1.1. HashMap simples (single-thread)

\n

Para aplicações single-thread, o HashMap comum é adequado. Exemplo:

\n
use std::collections::HashMap;\n\nfn main() {\n    let mut cache: HashMap<String, String> = HashMap::new();\n    cache.insert("user:1".to_string(), "Alice".to_string());\n    \n    if let Some(name) = cache.get("user:1") {\n        println!("Valor em cache: {}", name);\n    }\n}
\n

Vantagens: código mínimo, sem dependências.
\nDesvantagens: sem TTL, não é thread-safe, memória ilimitada.

\n\n

1.2. Cache thread-safe com Mutex e Arc

\n

Para aplicações multithread, use Arc<Mutex<HashMap>>:

\n
use std::collections::HashMap;\nuse std::sync::{Arc, Mutex};\nuse std::thread;\n\nstruct Cache {\n    store: Arc<Mutex<HashMap<String, String>>>,\n}\n\nimpl Cache {\n    fn new() -> Self {\n        Cache { store: Arc::new(Mutex::new(HashMap::new())) }\n    }\n    \n    fn get(&self, key: &str) -> Option<String> {\n        self.store.lock().ok()?.get(key).cloned()\n    }\n    \n    fn set(&self, key: String, value: String) {\n        self.store.lock().unwrap().insert(key, value);\n    }\n}\n\nfn main() {\n    let cache = Cache::new();\n    let c1 = cache.clone();\n    thread::spawn(move || {\n        c1.set("key".to_string(), "value".to_string());\n    });\n    println!("{:?}", cache.get("key"));\n}
\n

Desvantagem: o bloqueio do Mutex pode reduzir o desempenho em alta concorrência.

\n\n

1.3. Bibliotecas avançadas: lru e cached

\n

Para código em produção, é melhor usar crates prontos:

\n
    \n
  • lru — implementa o algoritmo de despejo LRU (Least Recently Used). Adequado para cache limitado.
  • \n
  • cached — fornece macros para cache automático de funções com suporte a TTL e LRU.
  • \n
\n

Exemplo com cached:

\n
use cached::proc_macro::cached;\n\n#[cached(size = 100, time = 300)]\nfn expensive_computation(x: u32) -> u32 {\n    std::thread::sleep(std::time::Duration::from_secs(2));\n    x * x\n}\n\nfn main() {\n    let result = expensive_computation(5); // leva 2 segundos\n    let cached_result = expensive_computation(5); // instantâneo\n    println!("{}", cached_result);\n}
\n\n

2. Redis: cache distribuído para sistemas escaláveis

\n

Redis é um armazenamento de dados in-memory, ideal para cache distribuído. Em Rust, usa-se o crate redis para trabalhar com Redis.

\n\n

2.1. Conexão e operações básicas

\n
use redis::Commands;\n\nfn main() -> redis::RedisResult<()> {\n    let client = redis::Client::open("redis://127.0.0.1:6379/")?;\n    let mut con = client.get_connection()?;\n    \n    // Definir valor com TTL (tempo de vida)\n    con.set_ex("user:1", "Alice", 3600)?; //                

Blogs

Book Recommendations