Caché en Rust: Redis, Memcached y soluciones integradas

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: ¿Por qué usar caché en Rust?

\n

La velocidad es la principal ventaja de Rust. Pero incluso el código más rápido puede verse limitado por la entrada/salida (E/S) lenta: consultas a bases de datos, APIs externas o cálculos de datos complejos. El caché resuelve este problema almacenando los resultados de operaciones costosas en un almacenamiento rápido. Rust ofrece herramientas flexibles para el caché: desde estructuras de datos integradas simples hasta potentes sistemas distribuidos como Redis y Memcached.

\n

En este artículo, analizaremos todos los niveles de caché en Rust: desde un simple HashMap hasta soluciones profesionales con TTL (tiempo de vida) y sincronización. Aprenderás a elegir la herramienta adecuada para tu proyecto y evitar errores comunes.

\n\n

1. Caché integrado: HashMap y sus variantes

\n

La forma más simple de caché en Rust es usar HashMap de la biblioteca estándar. Sin embargo, en entornos multihilo se necesitan mecanismos de sincronización adicionales.

\n\n

1.1. HashMap simple (monohilo)

\n

Para aplicaciones monohilo, es adecuado un HashMap normal. Ejemplo:

\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 en caché: {}", name);\n    }\n}
\n

Ventajas: código mínimo, sin dependencias.
\nDesventajas: sin TTL, no es seguro para hilos, memoria ilimitada.

\n\n

1.2. Caché seguro para hilos con Mutex y Arc

\n

Para aplicaciones multihilo, usa 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

Desventaja: el bloqueo de Mutex puede reducir el rendimiento en alta concurrencia.

\n\n

1.3. Bibliotecas avanzadas: lru y cached

\n

Para código en producción, es mejor usar crates ya preparados:

\n
    \n
  • lru — implementa el algoritmo de expulsión LRU (Menos Usado Recientemente). Adecuado para caché limitado.
  • \n
  • cached — proporciona macros para el caché automático de funciones con soporte de TTL y LRU.
  • \n
\n

Ejemplo con 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); // tarda 2 seg\n    let cached_result = expensive_computation(5); // instantáneo\n    println!("{}", cached_result);\n}
\n\n

2. Redis: caché distribuido para sistemas escalables

\n

Redis es un almacén de datos en memoria, ideal para caché distribuido. En Rust, se usa el crate redis para trabajar con Redis.

\n\n

2.1. Conexión y operaciones 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    // Establecer valor con TTL (tiempo de vida)\n    con.set_ex("user:1", "Alice", 3600)?; //                

Blogs

Book Recommendations