跳到主要内容

设计缓存系统

问题

如何用 Rust 设计一个高性能的内存缓存系统?

答案

架构设计

LRU + TTL 缓存实现

use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use std::time::{Duration, Instant};

struct CacheEntry<V> {
value: V,
expires_at: Instant,
}

pub struct Cache<K, V> {
inner: Arc<RwLock<HashMap<K, CacheEntry<V>>>>,
default_ttl: Duration,
}

impl<K: Eq + std::hash::Hash + Clone, V: Clone> Cache<K, V> {
pub fn new(default_ttl: Duration) -> Self {
let cache = Self {
inner: Arc::new(RwLock::new(HashMap::new())),
default_ttl,
};
// 启动后台清理过期条目
cache.start_cleanup();
cache
}

pub fn get(&self, key: &K) -> Option<V> {
let map = self.inner.read().unwrap();
map.get(key)
.filter(|entry| entry.expires_at > Instant::now())
.map(|entry| entry.value.clone())
}

pub fn set(&self, key: K, value: V) {
let mut map = self.inner.write().unwrap();
map.insert(key, CacheEntry {
value,
expires_at: Instant::now() + self.default_ttl,
});
}

fn start_cleanup(&self) {
let inner = self.inner.clone();
tokio::spawn(async move {
loop {
tokio::time::sleep(Duration::from_secs(60)).await;
let mut map = inner.write().unwrap();
let now = Instant::now();
map.retain(|_, entry| entry.expires_at > now);
}
});
}
}

高性能优化:分片锁

use std::collections::HashMap;
use std::sync::RwLock;
use std::hash::{Hash, Hasher, DefaultHasher};

/// 分片缓存:减少锁竞争
pub struct ShardedCache<K, V> {
shards: Vec<RwLock<HashMap<K, V>>>,
shard_count: usize,
}

impl<K: Hash + Eq, V> ShardedCache<K, V> {
pub fn new(shard_count: usize) -> Self {
let shards = (0..shard_count)
.map(|_| RwLock::new(HashMap::new()))
.collect();
Self { shards, shard_count }
}

fn get_shard(&self, key: &K) -> &RwLock<HashMap<K, V>> {
let mut hasher = DefaultHasher::new();
key.hash(&mut hasher);
let index = hasher.finish() as usize % self.shard_count;
&self.shards[index]
}

pub fn get(&self, key: &K) -> Option<V> where V: Clone {
let shard = self.get_shard(key).read().unwrap();
shard.get(key).cloned()
}

pub fn insert(&self, key: K, value: V) {
let mut shard = self.get_shard(&key).write().unwrap();
shard.insert(key, value);
}
}

缓存策略对比

策略适用场景Rust 实现
LRU通用缓存lru crate
LFU热点数据moka crate
TTL时效性数据自定义 + Instant
ARC自适应moka (内置)
推荐库

moka 是 Rust 最佳的并发缓存库,基于 Java Caffeine 算法,支持 TTL、容量限制、异步加载。


常见面试问题

Q1: 缓存穿透、击穿、雪崩怎么处理?

答案

问题描述Rust 解决方案
穿透查询不存在的 key布隆过滤器 / 缓存空值
击穿热点 key 过期mokaget_with 自动加载(单线程加载)
雪崩大量 key 同时过期TTL 加随机偏移

mokaget_with 内置了防击穿:多个线程同时请求同一个 key,只有一个会执行加载函数,其他等待结果。

相关链接