<div align="center">
# ๐ Oxcache
[](https://github.com/Kirky-X/oxcache/actions/workflows/ci.yml)
[](https://crates.io/crates/oxcache)
[](https://docs.rs/oxcache)
[](https://crates.io/crates/oxcache)
[](https://codecov.io/gh/Kirky-X/oxcache)
[](https://deps.rs/repo/github/Kirky-X/oxcache)
[](https://github.com/Kirky-X/oxcache/blob/main/LICENSE)
[](https://www.rust-lang.org)
้ซๆง่ฝใ็ไบง็บง็ Rust ๅๅฑ็ผๅญๅบ๏ผๆไพ L1๏ผMoka ๅ
ๅญ็ผๅญ๏ผ+ L2๏ผRedis ๅๅธๅผ็ผๅญ๏ผๅๅฑๆถๆใ
</div>
## โจ ๆ ธๅฟ็นๆง
<div align="center">
<table>
<tr>
<td width="20%" align="center">
<img src="https://img.icons8.com/fluency/96/000000/rocket.png" width="48"><br>
<b>ๆ่ดๆง่ฝ</b><br>L1 ็บณ็ง็บงๅๅบ
</td>
<td width="20%" align="center">
<img src="https://img.icons8.com/fluency/96/000000/magic-wand.png" width="48"><br>
<b>้ถไพตๅ
ฅๅผ</b><br>ไธ่กไปฃ็ ๅฏ็จ็ผๅญ
</td>
<td width="20%" align="center">
<img src="https://img.icons8.com/fluency/96/000000/cloud.png" width="48"><br>
<b>่ชๅจๆ
้ๆขๅค</b><br>Redis ๆ
้่ชๅจ้็บง
</td>
<td width="20%" align="center">
<img src="https://img.icons8.com/fluency/96/000000/synchronize.png" width="48"><br>
<b>ๅคๅฎไพๅๆญฅ</b><br>ๅบไบ Pub/Sub ๆบๅถ
</td>
<td width="20%" align="center">
<img src="https://img.icons8.com/fluency/96/000000/lightning.png" width="48"><br>
<b>ๆน้ไผๅ</b><br>ๆบ่ฝๆน้ๅๅ
ฅ
</td>
</tr>
</table>
</div>
- **๐ ๆ่ดๆง่ฝ**: L1 ็บณ็ง็บงๅๅบ๏ผP99 < 100ns๏ผ๏ผL2 ๆฏซ็ง็บงๅๅบ๏ผP99 < 5ms๏ผ
- **๐ฏ ้ถไพตๅ
ฅๅผ**: ้่ฟ `#[cached]` ๅฎไธ่กไปฃ็ ๅฏ็จ็ผๅญ
- **๐ ่ชๅจๆ
้ๆขๅค**: Redis ๆ
้ๆถ่ชๅจ้็บง๏ผๆขๅคๅ่ชๅจ้ๆพ WAL
- **๐ ๅคๅฎไพๅๆญฅ**: ๅบไบ Pub/Sub + ็ๆฌๅท็ๅคฑๆๅๆญฅๆบๅถ
- **โก ๆน้ไผๅ**: ๆบ่ฝๆน้ๅๅ
ฅ๏ผๅคงๅน
ๆๅๅๅ้
- **๐ก๏ธ ็ไบง็บงๅฏ้ **: ๅฎๆด็ๅฏ่งๆตๆงใๅฅๅบทๆฃๆฅใๆททๆฒๆต่ฏ้ช่ฏ
## ๐ฆ ๅฟซ้ๅผๅง
### ๅฎ่ฃ
ๅจ `Cargo.toml` ไธญๆทปๅ ไพ่ต๏ผ
```toml
[dependencies]
oxcache = "0.1"
```
> **ๆณจๆ**๏ผ`tokio` ๅ `serde` ๅทฒ้ป่ฎคๅ
ๅซใๅฆๆ้่ฆๆๅฐไพ่ต๏ผๅฏไปฅไฝฟ็จ
`oxcache = { version = "0.1", default-features = false }` ๆๅจๆทปๅ ใ
### ๆ็ฎ็คบไพ
```rust
use oxcache::macros::cached;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug)]
struct User {
id: u64,
name: String,
}
// ไธ่กไปฃ็ ๅฏ็จ็ผๅญ
#[cached(service = "user_cache", ttl = 600)]
async fn get_user(id: u64) -> Result<User, String> {
// ๆจกๆ่ๆถ็ๆฐๆฎๅบๆฅ่ฏข
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
Ok(User {
id,
name: format!("User {}", id),
})
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// ๅๅงๅ็ผๅญ๏ผไป้
็ฝฎๆไปถๅ ่ฝฝ๏ผ
oxcache::init("config.toml").await?;
// ็ฌฌไธๆฌก่ฐ็จ๏ผๆง่กๅฝๆฐ้ป่พ + ็ผๅญ็ปๆ๏ผ~100ms๏ผ
let user = get_user(1).await?;
println!("First call: {:?}", user);
// ็ฌฌไบๆฌก่ฐ็จ๏ผ็ดๆฅไป็ผๅญ่ฟๅ๏ผ~0.1ms๏ผ
let cached_user = get_user(1).await?;
println!("Cached call: {:?}", cached_user);
Ok(())
}
```
### ้
็ฝฎๆไปถ
ๅๅปบ `config.toml`๏ผ
```toml
[global]
default_ttl = 3600
health_check_interval = 30
serialization = "json"
enable_metrics = true
[services.user_cache]
cache_type = "two-level" # "l1" | "l2" | "two-level"
ttl = 600
[services.user_cache.l1]
max_capacity = 10000
ttl = 300 # L1 TTL ๅฟ
้กป <= L2 TTL
tti = 180
initial_capacity = 1000
[services.user_cache.l2]
[services.user_cache.two_level]
write_through = true
promote_on_hit = true
enable_batch_write = true
batch_size = 100
batch_interval_ms = 50
```
## ๐จ ไฝฟ็จๅบๆฏ
### ๅบๆฏ 1: ็จๆทไฟกๆฏ็ผๅญ
```rust
#[cached(service = "user_cache", ttl = 600)]
async fn get_user_profile(user_id: u64) -> Result<UserProfile, Error> {
database::query_user(user_id).await
}
```
### ๅบๆฏ 2: API ๅๅบ็ผๅญ
```rust
#[cached(
service = "api_cache",
ttl = 300,
key = "api_{endpoint}_{version}"
)]
async fn fetch_api_data(endpoint: String, version: u32) -> Result<ApiResponse, Error> {
http_client::get(&format!("/api/{}/{}", endpoint, version)).await
}
```
### ๅบๆฏ 3: ไป
L1 ็ญๆฐๆฎ็ผๅญ
```rust
#[cached(service = "session_cache", cache_type = "l1", ttl = 60)]
async fn get_user_session(session_id: String) -> Result<Session, Error> {
session_store::load(session_id).await
}
```
### ๅบๆฏ 4: ๆๅจๆงๅถ็ผๅญ
```rust
use oxcache::{get_client, CacheOps};
async fn advanced_caching() -> Result<(), Box<dyn std::error::Error>> {
let client = get_client("custom_cache")?;
// ๆ ๅๆไฝ
client.set("key", &my_data, Some(300)).await?;
let data: MyData = client.get("key").await?.unwrap();
// ไป
ๅๅ
ฅ L1๏ผไธดๆถๆฐๆฎ๏ผ
client.set_l1_only("temp_key", &temp_data, Some(60)).await?;
// ไป
ๅๅ
ฅ L2๏ผๅ
ฑไบซๆฐๆฎ๏ผ
client.set_l2_only("shared_key", &shared_data, Some(3600)).await?;
// ๅ ้ค
client.delete("key").await?;
Ok(())
}
```
## ๐๏ธ ๆถๆ่ฎพ่ฎก
```
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Application Code โ
โ (#[cached] Macro) โ
โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ CacheManager โ
โ (Service Registry + Health Monitor) โ
โโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโ
โ โ
โ โ
โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ
โ TwoLevelClientโ โ L1OnlyClient โ
โ โ โ L2OnlyClient โ
โโโโโฌโโโโโโโฌโโโโ โโโโโโโโโโโโโโโโ
โ โ
โ โ
โโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ L1 โ โ L2 โ
โ (Moka) โ โ (Redis) โ
โ โ โ โ
โโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
**L1**: ่ฟ็จๅ
้ซ้็ผๅญ๏ผไฝฟ็จ LRU/TinyLFU ๆทๆฑฐ็ญ็ฅ
**L2**: ๅๅธๅผๅ
ฑไบซ็ผๅญ๏ผๆฏๆ Sentinel/Cluster ๆจกๅผ
## ๐ ๆง่ฝๅบๅ
> ๆต่ฏ็ฏๅข: M1 Pro, 16GB RAM, macOS
```
ๅ็บฟ็จๅปถ่ฟๆต่ฏ (P99):
โโโ L1 ็ผๅญ: ~50ns
โโโ L2 ็ผๅญ: ~1ms
โโโ ๆฐๆฎๅบ: ~10ms
ๅๅ้ๆต่ฏ (batch_size=100):
โโโ ๅๆฌกๅๅ
ฅ: ~10K ops/s
โโโ ๆน้ๅๅ
ฅ: ~50K ops/s
```
## ๐ก๏ธ ๅฏ้ ๆง
- โ
ๅๆฌก่ฏทๆฑๅป้ (Single-Flight)
- โ
้ขๅๆฅๅฟ (WAL) ๆไน
ๅ
- โ
Redis ๆ
้่ชๅจ้็บง
- โ
ไผ้
ๅ
ณ้ญๆบๅถ
- โ
ๅฅๅบทๆฃๆฅไธ่ชๅจๆขๅค
## ๐ ๆๆกฃ
- [๐ ็จๆทๆๅ](docs/zh/USER_GUIDE.md)
- [๐ API ๆๆกฃ](https://docs.rs/oxcache)
- [๐ป ็คบไพไปฃ็ ](../examples/)
## ๐ค ่ดก็ฎ
ๆฌข่ฟๆไบค Pull Request ๅ Issue๏ผ
## ๐ ๆดๆฐๆฅๅฟ
่ฏฆ่ง [CHANGELOG.md](../CHANGELOG.md)
## ๐ ่ฎธๅฏ่ฏ
ๆฌ้กน็ฎ้็จ MIT ่ฎธๅฏ่ฏใ่ฏฆ่ง [LICENSE](../LICENSE) ๆไปถใ
---
<div align="center">
**ๅฆๆ่ฟไธช้กน็ฎๅฏนไฝ ๆๅธฎๅฉ๏ผ่ฏท็ปไธช โญ Star ๆฏๆไธไธ๏ผ**
Made with โค๏ธ by oxcache Team
</div>