Caching in Rust: Redis and Other Efficient Solutions
In modern high-load development with Rust, caching plays a key role. It reduces the load on databases, speeds up API responses, and optimizes work with expensive computations. In this article, we will look at the main libraries for caching in the Rust ecosystem: from powerful Redis to lightweight in-memory solutions.
1. Redis via the redis-rs Crate
redis-rs is the primary and most mature library for working with Redis in Rust. It supports asynchronous operations (via tokio or async-std), clustering, pub/sub, and all popular Redis data types.
Installation
[dependencies]redis = { version = "0.25", features = ["tokio-comp"] }tokio = { version = "1", features = ["full"] }Basic Example: Caching Strings
use redis::AsyncCommands;
#[tokio::main]async fn main() -> redis::RedisResult<()> { let client = redis::Client::open("redis://127.0.0.1:6379/")?; let mut con = client.get_multiplexed_async_connection().await?;
// Set cache with TTL of 60 seconds let _: () = con.set_ex("user:123", "{\\"name\\":\\"Alice\\"}", 60).await?;
// Get the value let cached: String = con.get("user:123").await?; println!("Cached data: {}", cached);
// Check if key exists let exists: bool = con.exists("user:123").await?; println!("Key exists: {}", exists);
Ok(())}Serializing Complex Structures
To cache data structures, use serde together with redis:
use serde::{Serialize, Deserialize};use redis::AsyncCommands;
#[derive(Debug, Serialize, Deserialize)]struct User { id: u32, name: String, email: String,}
async fn cache_user(con: &mut redis::aio::MultiplexedConnection, user: &User) { let json = serde_json::to_string(user).unwrap(); let _: () = con.set_ex(format!("user:{}", user.id), json, 300).await.unwrap();}
async fn get_cached_user(con: &mut redis::aio::MultiplexedConnection, id: u32) -> Option<User> { let json: Option<String> = con.get(format!("user:{}", id)).await.unwrap(); json.and_then(|data| serde_json::from_str(&data).ok())}2. In-memory Caching: The moka Crate
Moka is a high-performance in-memory caching library inspired by Caffeine (Java). It is ideal for scenarios where an external server is not required and maximum speed is needed.
Features of moka:
- Automatic eviction by time (TTL, TTI) and by size
- Asynchronous refresh (background refresh)
- Thread-safe for multi-threaded use (Arc + RwLock)
- Support for weighted cache policies
Example: Cache with TTL and Size Limit
use moka::sync::Cache;use std::time::Duration;
fn main() { // Create a cache for 1000 items with a TTL of 10 minutes let cache: Cache<String, String> = Cache::builder() .max_capacity(1000) .time_to_live(Duration::from_secs(600)) .build();
// Insert and retrieve cache.insert("key1".to_string(), "value1".to_string()); if let Some(v) = cache.get("key1") { println!("Value: {}", v); }}Asynchronous Variant (moka::future::Cache)
use moka::future::Cache;
#[tokio::main]async fn main() { let cache: Cache<u64, String> = Cache::new(10_000);
// Asynchronous insertion cache.insert(42, "Hello async".to_string()).await;
// Asynchronous retrieval if let Some(val) = cache.get(&42).await { println!("{}", val); }}3. Declarative Caching: The <
Also in library
JSON Processing in C# (.NET): Complete Guide to Newtonsoft.Json and System.Text.Json
Data Validation in Rust: validator Library
Thymeleaf for Java: Complete Guide with Examples
Sending Email in C# (.NET) Using SmtpClient and MailKit