Rust中的缓存:Redis及其他高效解决方案
在现代高负载的Rust开发中,缓存扮演着关键角色。它可以降低数据库负载、加速API响应并优化昂贵计算的处理。本文将介绍Rust生态系统中的主要缓存库:从强大的Redis到轻量级的内存解决方案。
1. 通过crate redis-rs使用Redis
redis-rs 是Rust中用于操作Redis的主要且最成熟的库。它支持异步操作(通过tokio或async-std)、集群、发布/订阅以及所有流行的Redis数据类型。
安装
[dependencies]redis = { version = "0.25", features = ["tokio-comp"] }tokio = { version = "1", features = ["full"] }基础示例:字符串缓存
use redis::AsyncCommands;
#[tokio::main]async fn main() -> redis::RedisResult<()> { let client = redis::Client::open("redis://127.0.0.1:6379/")?; let mut con = client.get_multiplexed_async_connection().await?;
// 设置TTL为60秒的缓存 let _: () = con.set_ex("user:123", "{\\"name\\":\\"Alice\\"}", 60).await?;
// 获取值 let cached: String = con.get("user:123").await?; println!("缓存数据: {}", cached);
// 检查键是否存在 let exists: bool = con.exists("user:123").await?; println!("键存在: {}", exists);
Ok(())}复杂结构的序列化
要缓存数据结构,请将serde与redis结合使用:
use serde::{Serialize, Deserialize};use redis::AsyncCommands;
#[derive(Debug, Serialize, Deserialize)]struct User { id: u32, name: String, email: String,}
async fn cache_user(con: &mut redis::aio::MultiplexedConnection, user: &User) { let json = serde_json::to_string(user).unwrap(); let _: () = con.set_ex(format!("user:{}", user.id), json, 300).await.unwrap();}
async fn get_cached_user(con: &mut redis::aio::MultiplexedConnection, id: u32) -> Option<User> { let json: Option<String> = con.get(format!("user:{}", id)).await.unwrap(); json.and_then(|data| serde_json::from_str(&data).ok())}2. 内存缓存:crate moka
Moka 是一个高性能的内存缓存库,灵感来自Caffeine (Java)。它非常适合不需要外部服务器、追求极致速度的场景。
moka的特点:
- 基于时间(TTL、TTI)和大小的自动淘汰
- 异步同步(后台刷新)
- 多线程安全(Arc + RwLock)
- 支持权重策略(weighted cache)
示例:带TTL和大小限制的缓存
use moka::sync::Cache;use std::time::Duration;
fn main() { // 创建一个最多1000个元素、TTL为10分钟的缓存 let cache: Cache<String, String> = Cache::builder() .max_capacity(1000) .time_to_live(Duration::from_secs(600)) .build();
// 插入和获取 cache.insert("key1".to_string(), "value1".to_string()); if let Some(v) = cache.get("key1") { println!("值: {}", v); }}异步版本 (moka::future::Cache)
use moka::future::Cache;
#[tokio::main]async fn main() { let cache: Cache<u64, String> = Cache::new(10_000);
// 异步插入 cache.insert(42, "Hello async".to_string()).await;
// 异步获取 if let Some(val) = cache.get(&42).await { println!("{}", val); }}