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, Memcached, and Built-in Solutions



Caching is one of the key mechanisms for optimizing the performance of modern applications. In the Rust ecosystem, known for its speed and memory safety, choosing the right caching tool can significantly impact program efficiency. In this article, we will look at three main approaches: external systems Redis and Memcached, as well as built-in solutions available in the standard library and popular crates.



Why cache in Rust?

Rust itself is already very fast, but when working with databases, external APIs, or complex computations, caching allows you to:

  • Reduce latency on repeated requests
  • Decrease load on databases and external services
  • Save computational resources and CPU time


1. Built-in Solutions: HashMap and LRU Cache

The simplest way to cache in Rust is using HashMap from the standard library. For multithreaded applications, a Mutex<HashMap> or RwLock<HashMap> wrapper is required. However, this approach lacks an eviction policy, which can lead to infinite memory growth.



Example of a simple cache using HashMap

use std::collections::HashMap;use std::sync::Mutex;

struct SimpleCache { store: Mutex<HashMap<String, String>>,}

impl SimpleCache { fn new() -> Self { SimpleCache { store: Mutex::new(HashMap::new()), } }

fn get(&self, key: &str) -> Option<String> { self.store.lock().unwrap().get(key).cloned() }

fn set(&self, key: String, value: String) { self.store.lock().unwrap().insert(key, value); }}


LRU Cache via the lru crate

To limit the cache size and automatically evict old entries, use the lru crate. It implements the Least Recently Used algorithm — removing the least frequently used items.



use lru::LruCache;use std::num::NonZeroUsize;

fn main() { let mut cache = LruCache::new(NonZeroUsize::new(3).unwrap()); cache.put("apple", 10); cache.put("banana", 20); cache.put("cherry", 30); cache.put("date", 40); // "apple" will be evicted

println!("{:?}", cache.get(&"apple")); // None println!("{:?}", cache.get(&"date")); // Some(40)}


Pros: zero network latency, simplicity, full control. Cons: cache lives only within a single process, no persistence.



2. Caching with Redis via redis-rs

Redis is an in-memory key-value store, often used as a distributed cache. In Rust, the redis crate (or redis-rs) is used to work with Redis.



Connection and basic operations

use redis::Commands;

fn main() -> redis::RedisResult<()> { let client = redis::Client::open("redis://127.0.0.1:6379/")?; let mut con = client.get_connection()?;

// Set value with TTL (time to live) con.set_ex("user:42", "{\\"name\\": \\"Alice\\"}", 60)?;

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

// Check existence let exists: bool = con.exists("user:42")?; println!("Exists: {}", exists);

Ok(())}


Advanced Redis features

  • TTL (Time To Live): automatic deletion of expired entries
  • Data structures: lists, sets, hashes — for complex scenarios
  • Pub/Sub: notifications about cache changes
  • Clustering: horizontal scaling


Pros: dis

Blogs

Book Recommendations