Rust中的缓存:Redis、Memcached及内置解决方案(高级水平)

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:为什么在Rust中缓存既是挑战也是优势

在基于Rust的高负载系统中,缓存不再仅仅是添加一个库那么简单。由于严格的所有权系统、没有垃圾回收器以及对线程安全的要求,传统方法需要重新思考。然而,Rust提供了独特的能力:可预测的响应时间、零GC开销以及对内存的完全控制。在本文中,我们将深入探讨高级缓存技术:从分布式解决方案(Redis、Memcached)到内置缓存(moka、lru)及其组合。



1. 通过deadpool-redis实现与Redis的异步交互

1.1. 为什么不直接使用redis-rs?

redis-rs客户端是同步的。对于基于tokio的异步应用程序,需要一个连接池。deadpool-redis提供了一个异步连接池,用于管理连接并在发生故障时自动重新连接。



1.2. 示例:带TTL和序列化的缓存

use deadpool_redis::{Config, Runtime, Pool};use serde::{Serialize, Deserialize};use tokio::sync::OnceCell;

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

async fn get_pool() -> Pool { static POOL: OnceCell<Pool> = OnceCell::const_new(); POOL.get_or_init(|| async { let cfg = Config::from_url("redis://127.0.0.1/"); cfg.create_pool(Some(Runtime::Tokio1)).unwrap() }).await.clone()}

async fn get_user_cached(user_id: u64) -> Option<User> { let pool = get_pool().await; let mut conn = pool.get().await.unwrap(); let key = format!("user:{}", user_id);

// 尝试从缓存读取 if let Ok(Some(data)) = redis::cmd("GET").arg(&key).query_async::<Option<Vec<u8>>>(&mut conn).await { if let Ok(user) = bincode::deserialize::<User>(&data) { return Some(user); } } None}

async fn set_user_cache(user: &User) { let pool = get_pool().await; let mut conn = pool.get().await.unwrap(); let key = format!("user:{}", user.id); let data = bincode::serialize(user).unwrap();

// TTL 300秒 let _: () = redis::cmd("SETEX") .arg(&key) .arg(300) .arg(&data) .query_async(&mut conn) .await .unwrap();}


1.3. 高级策略:带锁的Cache-Aside模式

当遇到缓存雪崩(大量请求同时尝试重新填充缓存)时,在应用层使用互斥锁:

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

struct CacheLock { locks: Mutex<HashMap<String, tokio::sync::Semaphore>>,}

impl CacheLock { async fn get_or_compute<F, Fut, T>(&self, key: &str, f: F) -> T where F: FnOnce() -> Fut, Fut: Future<Output = T>, { let sem = { let mut map = self.locks.lock().await; map.entry(key.to_string()) .or_insert_with(|| tokio::sync::Semaphore::new(1)) .clone() }; let _permit = sem.acquire().await.unwrap(); f().await }}


2. Memcached:使用memcache-async实现轻量与高速

2.1. Rust中Memcached的特点

Memcached比Redis更简单:没有持久化和复杂的数据结构,但对于简单的键值操作更快。memcache-async crate提供了一个基于tokio的异步客户端。



2.2. 示例:批量加载与流水线操作

use memcache_async::{Client, Protocol, Value};use bytes::Bytes;

#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { let client = Client::connect_async("memcache://127.0.0.1:11211").await?;

// 批

博客

书籍推荐