Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
English | 简体中文
高性能、生产级的 Rust 双层缓存库,提供 L1(Moka 内存缓存)+ L2(Redis 分布式缓存)双层架构。
✨ 核心特性
- 🚀 极致性能: L1 纳秒级响应(P99 < 100ns),L2 毫秒级响应(P99 < 5ms)
- 🎯 零侵入式: 通过
#[cached]宏一行代码启用缓存 - 🔄 自动故障恢复: Redis 故障时自动降级,恢复后自动重放 WAL
- 🌐 多实例同步: 基于 Pub/Sub + 版本号的失效同步机制
- ⚡ 批量优化: 智能批量写入,大幅提升吞吐量
- 🧪 同步 API: 在异步 API 之外提供同步路径
get_sync/set_sync/get_or_sync,在multi_threadtokio 上无需运行时 - 🌸 布隆过滤器: 可选的
BloomFilterBackend装饰器以 O(1) 成本过滤负查询,跳过 inner 后端 - ⏱️ 全局 per-entry TTL: 所有后端(Moka / DashMap / Redis / Mock / Chain / Bloom)都遵守 per-entry
set(key, value, Some(ttl)) - 🛡️ 生产级可靠: 完整的可观测性、健康检查、混沌测试验证
📦 快速开始
安装
在 Cargo.toml 中添加依赖:
[]
= "0.3.2"
注意:
tokio和serde已默认包含。如果需要最小依赖,可以使用oxcache = { version = "0.3.2", default-features = false }手动添加。
特性:要使用
#[cached]宏,需要启用macros特性:oxcache = { version = "0.3.2", features = ["macros"] }
特性分层
# 完整特性(推荐)
= { = "0.3.2", = ["full"] }
# 核心功能(L1 + L2 缓存)
= { = "0.3.2", = ["core"] }
# 最小特性(仅 L1 缓存)
= { = "0.3.2", = ["minimal"] }
# 自定义选择
= { = "0.3.2", = ["core", "macros", "metrics", "bloom-filter"] }
可用特性
| 层级 | 包含特性 | 描述 |
|---|---|---|
| minimal | memory, tokio/time, tracing, metrics, serialization, chrono |
仅 L1 缓存 |
| core | minimal + redis, futures |
L1 + L2 缓存 |
| full | core + macros, compression, batch-write, lua-script, cli, testing |
完整功能 |
独立特性:
memory- L1 缓存后端(Moka + DashMap)redis- L2 分布式缓存(Redis)macros-#[cached]属性宏serialization- JSON 序列化(serde + serde_json)compression- 数据压缩(flate2)metrics- OpenTelemetry 指标与可观测性batch-write- 优化的批量写入(tokio-util)lua-script- Lua 脚本执行支持cli- 命令行界面(clap)tracing- 结构化日志支持bloom-filter- 负查询过滤(BloomFilter + BloomFilterBackend);不在full中,需显式启用
最简示例
use cached;
use ;
use ;
// 一行代码启用缓存
async
async
配置文件
创建 config.toml:
[]
= 3600
= 30
= "json"
= true
# 双层缓存 (L1 + L2)
[]
= "two-level" # "l1" | "l2" | "two-level"
= 600
[]
= 10000
= 300 # L1 TTL 必须 <= L2 TTL
= 180
= 1000
[]
= "standalone" # "standalone" | "sentinel" | "cluster"
= "redis://127.0.0.1:6379"
[]
= true
= true
= true
= 100
= 50
# 仅 L1 缓存 (仅内存)
[]
= "l1"
= 300
[]
= 5000
= 300
= 120
# 仅 L2 缓存 (仅 Redis)
[]
= "l2"
= 7200
[]
= "standalone"
= "redis://127.0.0.1:6379"
类型安全配置 API(推荐)
Oxcache 提供类型安全的构建器 API 用于配置,支持编译时类型检查和更好的 IDE 支持。对于大多数用例,推荐使用此方式而非 TOML 配置。
仅内存缓存 (L1)
use UnifiedConfigBuilder;
use ;
use ;
async
分层缓存 (L1 + L2)
use UnifiedConfigBuilder;
use ;
use ;
async
配置构建器方法
| 方法 | 描述 |
|---|---|
Cache::builder() |
创建新的缓存构建器 |
.ttl(Duration) |
设置缓存条目的默认 TTL |
.tti(Duration) |
设置缓存条目的默认 TTI(time-to-idle) |
.capacity(u64) |
设置内存缓存容量 |
.backend_arc(Arc<dyn CacheBackend>) |
添加预构建后端(如 RedisBackend、MokaMemoryBackend) |
.sync_mode(bool) |
启用同步 API 支持(get_sync/set_sync/...) |
.build() |
构建 Cache<K, V> 实例(异步) |
注意: Redis 后端请使用
RedisBackend::new(url).await?然后通过.backend_arc(Arc::new(backend))传入。 分层缓存(L1+L2)请使用ChainCache::builder().link(...).build()。
类型安全 API 的优势
- 编译时验证:配置错误在编译时被捕获
- IDE 支持:完整的自动补全和类型提示
- 无运行时解析:消除 TOML 解析开销
- 更好的错误信息:类型错误而非配置解析错误
- 重构友好:重命名重构可在配置中生效
🎨 使用场景
场景 1: 用户信息缓存
async
场景 2: API 响应缓存
async
场景 3: 仅 L1 热数据缓存
async
场景 4: 手动控制缓存
use ;
use ;
async
🧪 同步 API(0.3.0)
Oxcache 0.3.0 在异步 API 之外引入了同步 API 路径。在 builder 上启用:
use Cache;
use ;
async
何时使用同步 API:
- 阻塞调用点(遗留代码、FFI、同步处理器)
- 不想在每个断言中穿过
async的测试 - 调用方本身是同步的,避免运行时开销
运行时注意事项:
sync_mode(true)在multi_threadtokio 运行时上工作。在current_thread运行时上,Moka 的sync_block_on会 panic(使用#[tokio::main(flavor = "multi_thread")]或在运行时上下文之外调用)。- 不启用
sync_mode(true)时,调用任何*_sync方法返回Err(CacheError::NotSupported)。
#[cached(sync)] 宏:
use cached;
🌸 布隆过滤器(0.3.0)
bloom-filter 特性(需显式启用;不在 full 中)提供负查询过滤:
[]
= { = "0.3.2", = ["memory", "bloom-filter"] }
use ;
use MokaMemoryBackend;
use ;
async
特性:
- 无假阴性(插入的 key 总是
contains == true) set更新 BF 和 inner;delete只更新 inner(BF 不支持删除)clear同时清空两者;TTL 原样透传- 当 inner 后端实现
SyncCacheBackend时,装饰器也实现
⏱️ TTL 行为对照表(0.3.0)
自 0.3.0 起所有后端都遵守 per-entry TTL。行为汇总:
| 后端 | set(ttl=Some) |
ttl(key) |
expire(key, new_ttl) |
说明 |
|---|---|---|---|---|
| MokaMemoryBackend | 通过 moka::Expiry 真实 per-entry TTL |
剩余 TTL | 更新 + 返回 true |
全局 TTL(builder.ttl(...))被 per-entry TTL 覆盖 |
| DashMapMemoryBackend | 存储 (value, expiry Instant);读取时懒过期 |
剩余 TTL(无 TTL 则 None) | 更新 + 返回 true |
懒过期 —— 条目在下次访问时移除 |
| RedisBackend | SET key value EX ttl |
TTL key(Redis 原生) |
EXPIRE key ttl |
使用 Redis 原生 TTL |
| MockBackend | 存储 (value, expiry Instant);懒过期 |
剩余 TTL | 更新 + 返回 true |
仅测试用;与 DashMap 语义对齐 |
| ChainCache | 将 ttl 透传到所有链接 |
返回拥有该 key 的最高分链接的 TTL | 透传到所有链接 | 所有链接接收相同 TTL |
| BloomFilterBackend | 将 ttl 透传到 inner(同时插入 key 到 BF) |
委托给 inner | 委托给 inner | BF 本身无 TTL 概念 |
全局 vs per-entry TTL:
MokaMemoryBackend::builder().ttl(Duration)设置应用于每个条目的全局 TTLset(key, value, Some(ttl))覆盖该条目的全局 TTLset(key, value, None)使用全局 TTL(若设置);否则条目永不过期
🏗️ 架构设计
graph TD
A[Application Code<br/>#[cached] Macro] --> B[Cache<K, V><br/>统一缓存接口]
B --> C[ChainCache<br/>分层后端]
B --> D[MokaMemoryBackend<br/>仅 L1]
B --> E[RedisBackend<br/>仅 L2]
C --> F[L1 Cache<br/>Moka]
C --> G[L2 Cache<br/>Redis]
D --> F
E --> G
style A fill:#e1f5fe
style B fill:#f3e5f5
style C fill:#e8f5e8
style D fill:#fff3e0
style E fill:#fce4ec
style F fill:#f1f8e9
style G fill:#fdf2e9
L1: 进程内高速缓存,使用 LRU/TinyLFU 淘汰策略 L2: 分布式共享缓存,支持 Sentinel/Cluster 模式
📊 性能基准
测试环境: M1 Pro, 16GB RAM, macOS, Redis 7.0
注意: 性能因硬件、网络条件和数据大小而异。
xychart-beta
title "单线程延迟测试 (P99)"
x-axis ["L1 缓存", "L2 缓存", "数据库"]
y-axis "延迟时间" 0 --> 60
bar [50, 3, 30]
line [50, 3, 30]
xychart-beta
title "吞吐量测试 (batch_size=100)"
x-axis ["L1 操作", "L2 单次写入", "L2 批量写入"]
y-axis "操作数/秒" 0 --> 600
bar [7500, 75, 350]
性能数据总结:
- L1 缓存: 50-100ns (内存访问)
- L2 缓存: 1-5ms (Redis, 本地)
- 数据库: 10-50ms (典型 SQL 查询)
- L1 操作: 5-10M ops/sec
- L2 单次写入: 50-100K ops/sec
- L2 批量写入: 200-500K ops/sec
🛡️ 可靠性
- ✅ 单次请求去重 (Single-Flight)
- ✅ 预写日志 (WAL) 持久化
- ✅ Redis 故障自动降级
- ✅ 优雅关闭机制
- ✅ 健康检查与自动恢复
🔐 安全性
Oxcache 实现了多项安全措施以防范常见攻击:
输入验证
所有用户输入在传递给 Redis 之前都会进行验证:
- 键验证:键不能为空、不能超过 512KB、不能包含危险字符(
\r、\n、\0),以防止 Redis 协议注入攻击。 - Lua 脚本验证:脚本验证包括:
- 最大长度 10KB
- 最多 100 个键
- 阻止危险命令:
FLUSHALL、FLUSHDB、KEYS、SHUTDOWN、DEBUG、CONFIG、SAVE、BGSAVE、MONITOR - 注释和字符串内容预处理,防止通过注释绕过检测
- SCAN 模式验证:模式验证以防止 ReDoS 攻击:
- 最大长度 256 个字符
- 最多 10 个通配符(
*)字符 - count 参数限制在安全范围内(1-1000)
- SQL/路径遍历检测:Redis 键会扫描潜在的 SQL 注入和路径遍历模式
安全 API(公共函数)
对于高级用例,您可以直接使用安全验证函数:
use ;
// 验证 Redis 键
validate_redis_key.expect;
// 验证 Lua 脚本
validate_lua_script.expect;
// 验证 SCAN 模式
validate_scan_pattern.expect;
超时保护
长时间运行的操作有超时保护:
- Lua 脚本:30 秒超时,防止 Redis 阻塞
- SCAN 操作:30 秒超时,防止扫描挂起
安全锁值
分布式锁使用库自动生成的加密安全 UUID v4 值,消除锁值预测攻击的风险。
连接字符串脱敏
连接字符串中的密码在日志中默认脱敏,以防止凭据泄露。使用 normalize_connection_string_with_redaction() 进行安全日志记录。
最佳实践
- 使用库的键验证 - 不要绕过
validate_redis_key()函数 - 避免自定义 Lua 脚本 - 尽可能使用内置缓存操作
- 设置适当的超时 - 不要禁用 30 秒默认超时
- 轮换锁值 - 库会自动处理
- 永远不要记录连接字符串 - 使用脱敏工具进行调试
更多详情请参阅 安全文档。
📚 文档
🤝 贡献
欢迎提交 Pull Request 和 Issue!
📝 更新日志
详见 CHANGELOG.md
📄 许可证
本项目采用 MIT 许可证。详见 LICENSE 文件。
如果这个项目对你有帮助,请给个 ⭐ Star 支持一下!
Made with ❤️ by Kirky.X