Caching in Rust: Redis, Memcached, and Built-in Solutions

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Caching in Rust: Redis and Other Tools for Application Acceleration

Caching is one of the key mechanisms for performance optimization. In Rust, with its emphasis on speed and safety, choosing the right caching tool can provide significant gains. This article covers popular libraries: redis-rs (with connection pooling), moka (in-memory cache), and cached (function decorators).



1. Redis: External Cache via redis-rs and deadpool

Redis is the most common external cache. The redis-rs crate is used to work with it in Rust. For production workloads, it is recommended to use a connection pool via deadpool-redis.



Installation

[dependencies]redis = { version = "0.25", features = ["tokio-comp"] }deadpool-redis = "0.14"tokio = { version = "1", features = ["full"] }serde = { version = "1", features = ["derive"] }serde_json = "1"


Example: Basic Redis Operations

use redis::AsyncCommands;use deadpool_redis::{Config, Runtime};

#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { // Create a connection pool let cfg = Config::from_url("redis://127.0.0.1:6379"); let pool = cfg.create_pool(Some(Runtime::Tokio1))?;

// Get a connection from the pool let mut conn = pool.get().await?;

// Set a value with TTL of 60 seconds conn.set_ex("user:42", "{\\"name\\":\\"Alice\\",\\"role\\":\\"admin\\"}", 60).await?;

// Read let value: String = conn.get("user:42").await?; println!("Retrieved: {}", value);

// Delete conn.del("user:42").await?;

Ok(())}


Struct Serialization

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]struct User { id: u64, name: String, email: String,}

async fn cache_user(conn: &mut redis::aio::Connection, user: &User) -> redis::RedisResult<()> { let key = format!("user:{}", user.id); let json = serde_json::to_string(user).unwrap(); conn.set_ex(key, json, 300).await}

async fn get_cached_user(conn: &mut redis::aio::Connection, id: u64) -> Option<User> { let key = format!("user:{}", id); let result: Option<String> = conn.get(key).await.ok()?; result.and_then(|json| serde_json::from_str(&json).ok())}


2. Moka: Fast In-Memory Cache

Moka is a high-performance in-memory cache inspired by Caffeine (Java). It supports TTL, size limits, and asynchronous updates.



Installation

[dependencies]moka = { version = "0.12", features = ["future"] }tokio = { version = "1", features = ["full"] }


Example: Cache with 1000 Element Limit and 10-Minute TTL

use moka::future::Cache;use std::time::Duration;

#[tokio::main]async fn main() { let cache: Cache<String, String> = Cache::builder() .max_capacity(1000) .time_to_live(Duration::from_secs(600)) .build();

// Insert cache.insert("key1".to_string(), "value1".to_string()).await;

// Read if let Some(v) = cache.get(&"key1".to_string()).await { println!("Found: {}", v); }

// Delete cache.invalidate(&"key1".to_string()).await;}


Auto-Refresh on TTL Expiry

let cache: Cache<String, String> = Cache::builder()    .time_to_live(Duration::from_secs(60))    .time_to_idle(Duration::from_secs(30)) // reset TTL on read    .build();


3. Cached: Function Decorators

The cached crate allows caching function results using attributes. It supports various backends, including Redis and in-memory.



Installation

[dependencies]cach                    

Recommendations