Caching in Rust: Redis, Memcached, and Built-in Solutions
Caching is one of the key mechanisms for optimizing the performance of web applications and high-load systems. The Rust ecosystem offers several powerful libraries for organizing caching: from distributed solutions (Redis, Memcached) to lightweight in-memory caches (moka, cached). In this article, we will thoroughly examine each of them, provide code examples, and compare their performance.
1. Redis via the redis-rs Crate
redis-rs is the primary and most mature client for Redis in Rust. It supports all major features: strings, lists, hashes, pub/sub, transactions, and clustering.
Installation
[dependencies]redis = { version = "0.25", features = ["tokio-comp"] }tokio = { version = "1", features = ["full"] }Example: Basic Caching with Redis
use redis::{AsyncCommands, Client};use std::time::Duration;
#[tokio::main]async fn main() -> redis::RedisResult<()> { let client = Client::open("redis://127.0.0.1:6379/")?; let mut con = client.get_multiplexed_async_connection().await?;
// Set a key with a TTL of 60 seconds con.set_ex("user:1:profile", "{\\"name\\":\\"Alice\\"}", 60).await?;
// Read the value let data: Option<String> = con.get("user:1:profile").await?; println!("Retrieved: {:?}", data);
// Increment a counter let count: i64 = con.incr("page_views", 1).await?; println!("Page views: {}", count);
Ok(())}Important features:
- Asynchronicity: redis-rs supports both synchronous and asynchronous (tokio/async-std) modes.
- Pipeline: grouping commands to reduce latency.
- Clustering: support for Redis Cluster via
redis::cluster.
2. Memcached via the memcached-rs Crate
Memcached is a lightweight distributed key-value store. For Rust, there is the memcached-rs crate (or memcache).
Usage Example
use memcache::Client;
fn main() -> memcache::MemcacheResult<()> { let client = Client::connect("memcache://127.0.0.1:11211")?;
// Write with TTL client.set("session:token_abc", "user_data", 30)?;
// Read let value: Option<String> = client.get("session:token_abc")?; println!("From Memcached: {:?}", value);
// Delete client.delete("session:token_abc")?;
Ok(())}When to choose Memcached over Redis:
- If you only need simple caching (key-value).
- If minimal latency is important (Memcached is faster than Redis for simple operations).
- If you don't need Redis data structures (lists, hashes, sets).
3. Built-in In-Memory Caches: moka and cached
For caching within a single process (without an external server), the moka and cached crates are excellent choices.
3.1 Moka — High-Performance Cache
moka is an asynchronous, thread-safe cache with support for TTL, maximum size, and eviction policies (LRU, LFU).
use moka::future::Cache;use std::time::Duration;
#[tokio::main]async fn main() { let cache: Cache<String, String> = Cache::builder() .max_capacity(10_000) // maximum 10,000 entries .time_to_live(Duration::from_secs(300)) // TTL 5 minutes .build();
// Insert cache.insert("key1".to_string(), "value1".to_string()).await;
// Retrieve if let Some(value) = cache.get(&"key1".to_string()).await { p