Rustash is a high-performance, feature-rich Redis caching library for Rust that provides:
- π Multi-tier caching - L1 in-memory (Moka) + L2 Redis for optimal performance
- π Redis Streams analytics - Track access patterns with bounded memory usage
- ποΈ Transparent compression - Automatic compression for large values (GZIP/LZ4/ZSTD)
- π₯ Cache warming - Intelligent preloading based on access patterns
- π OpenTelemetry metrics - Production-ready observability
- π οΈ Type-safe API - Full Serde integration with automatic serialization
- β‘ Async/await - Built for modern Rust applications
Add to your Cargo.toml:
[dependencies]
rustash = "0.1"Basic usage:
use rustash::{CacheBuilder, impl_cache_key};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct User {
id: u64,
name: String,
email: String,
}
// Automatic cache key generation
impl_cache_key!(User, |u: &User| format!("user:{}", u.id));
#[tokio::main]
async fn main() -> rustash::Result<()> {
// Create cache with fluent builder API
let cache = CacheBuilder::new("redis://localhost:6379")
.namespace("myapp")
.default_ttl_seconds(3600)
.build()
.await?;
let user = User {
id: 1,
name: "Alice".to_string(),
email: "alice@example.com".to_string(),
};
// Set and get with automatic serialization
cache.set("user:1", &user).await?;
let cached_user: Option<User> = cache.get("user:1").await?;
// Get-or-load pattern
let user = cache.get_or_load("user:2", async {
// Load from database
load_user_from_database(2).await
}).await?;
Ok(())
}Combine the speed of in-memory caching with the persistence of Redis:
let cache = CacheBuilder::new("redis://localhost:6379")
.enable_l1_cache(10000) // Hot data in memory
.enable_compression(1024) // Compress Redis values > 1KB
.default_ttl_seconds(3600)
.build()
.await?;
// L1 cache serves hot data at nanosecond latency
// L2 Redis cache handles larger dataset
// Automatic promotion/demotion between tiersPerformance comparison:
- Cold cache: ~500ms (database + compute)
- L2 hit (Redis): ~2ms (network + deserialization)
- L1 hit (memory): ~50ΞΌs (in-memory access)
Track cache usage patterns with Redis Streams and HyperLogLog:
use rustash::tracking::{AccessTracker, CacheAnalytics};
// Track access patterns
let tracker = AccessTracker::new(redis_connection, "access_stream").await?;
let analytics = CacheAnalytics::new(redis_connection, tracker, config).await?;
// Get insights
let stats = analytics.get_access_stats(TimePeriod::Daily(Utc::today())).await?;
println!("Unique keys accessed: {}", stats.unique_keys);
println!("Hit rate: {:.2}%", stats.performance.hit_rate * 100.0);Preload your cache based on data-driven insights:
use rustash::warming::{WarmingStrategy, CacheWarmer};
// Warm recently accessed items
cache.warm(WarmingStrategy::RecentlyAccessed {
hours: 24,
max_items: 1000,
}).await?;
// Warm by access patterns
cache.warm(WarmingStrategy::FrequentlyAccessed {
min_hits: 10,
max_items: 500,
}).await?;
// Schedule warming
let scheduler = WarmingScheduler::new(warmer);
scheduler.add_job(WarmingJob::new(
"morning_warm",
WarmingStrategy::RecentlyAccessed { hours: 24, max_items: 1000 },
WarmingSchedule::Daily { hour: 8 },
));Automatic compression with multiple algorithms:
let cache = CacheBuilder::new("redis://localhost:6379")
.enable_compression_with(
CompressionAlgorithm::Zstd, // or Gzip, Lz4
1024, // threshold: compress if > 1KB
6 // compression level
)
.build()
.await?;
// Transparently compresses large values
// Reduces Redis memory usage by 50-90%
// Automatic decompression on retrievalFull OpenTelemetry integration:
let cache = CacheBuilder::new("redis://localhost:6379")
.enable_metrics_with(MetricsConfig {
service_name: "my-service".to_string(),
otlp_endpoint: Some("http://jaeger:4317".to_string()),
..Default::default()
})
.build()
.await?;
// Automatic metrics:
// - cache_hits_total, cache_misses_total
// - cache_get_duration_seconds
// - cache_hit_rate
// - And many more...let cache = CacheBuilder::new("redis://localhost:6379")
// Basic settings
.namespace("myapp")
.default_ttl_seconds(3600)
.database(0)
// Multi-tier caching
.enable_l1_cache(10000) // L1 cache size
.enable_l1_cache_size_aware(10000, 100_000_000) // Size-aware eviction
// Compression
.enable_compression(1024) // Threshold in bytes
.enable_compression_with(algorithm, threshold, level)
// Connection pool
.connection_pool_size(2, 10) // min, max
.connection_timeout(Duration::from_secs(5))
// Timeouts
.timeouts(
Duration::from_secs(2), // read
Duration::from_secs(5), // write
Duration::from_secs(10), // batch
)
// Advanced features
.enable_metrics()
.enable_warming()
.enable_auto_refresh()
.enable_circuit_breaker()
.build()
.await?;// Development setup
let cache = CacheBuilder::development("redis://localhost:6379");
// High-performance setup
let cache = CacheBuilder::high_performance("redis://localhost:6379");
// Production-ready setup
let cache = CacheBuilder::production("redis://localhost:6379");use rustash::{CacheKey, impl_cache_key};
use std::time::Duration;
#[derive(Serialize, Deserialize)]
struct Product {
tenant_id: u32,
id: u64,
category: String,
}
// Advanced key implementation
impl_cache_key!(
Product,
|p: &Product| format!("product:{}:{}", p.tenant_id, p.id),
Duration::from_secs(7200), // Custom TTL
"products" // Namespace
);
// Use with the cache
let product = Product { tenant_id: 1, id: 123, category: "electronics".to_string() };
cache.set_by_key(&product).await?;
let cached = cache.get_by_key(&product).await?;// Efficient batch operations
let keys = ["user:1", "user:2", "user:3"];
let users: Vec<Option<User>> = cache.get_many(&keys).await?;
let entries = [("key1", &value1), ("key2", &value2)];
cache.set_many(&entries).await?;
let deleted_count = cache.delete_many(&keys.map(|s| s.to_string())).await?;use rustash::config::DataCategory;
// Different TTLs for different data types
cache.set_with_category("user:profile:1", &profile, DataCategory::Immutable).await?; // 24h
cache.set_with_category("user:session:1", &session, DataCategory::HighlyMutable).await?; // 5min
cache.set_with_category("user:prefs:1", &preferences, DataCategory::SemiMutable).await?; // 1huse rustash::namespace::{NamespaceRegistry, patterns};
// Multi-tenant application
let registry = patterns::multi_tenant("myapp");
let user_key = registry.key("users", "123")?; // "myapp:users:123"
// Microservices
let hierarchy = patterns::microservices("auth-service");
let session_key = hierarchy.path_key(&["sessions", "active"], "abc123")?;
// "auth-service:sessions:active:abc123"- Basic Usage - Fundamental operations
- Multi-Tier - L1+L2 caching with performance comparison
- Microservice - Production-ready setup
Run examples:
# Start Redis
docker run -d -p 6379:6379 redis:alpine
# Run examples
cargo run --example basic
cargo run --example multi_tier --features metrics[dependencies]
rustash = { version = "0.1", features = ["full"] }
# Or pick specific features:
rustash = { version = "0.1", features = [
"compression-gzip", # GZIP compression
"compression-lz4", # LZ4 compression
"compression-zstd", # ZSTD compression
"metrics", # OpenTelemetry metrics
"warming", # Cache warming
"auto-refresh", # Automatic refresh
"circuit-breaker", # Circuit breaker pattern
"rate-limiting", # Rate limiting
] }Benchmarks on M1 MacBook Pro with Redis 7.0:
| Operation | Throughput | Latency P50 | Latency P99 |
|---|---|---|---|
| L1 Get | 2M ops/sec | 50ΞΌs | 100ΞΌs |
| L2 Get | 50K ops/sec | 2ms | 5ms |
| Set | 45K ops/sec | 2.2ms | 6ms |
| Batch Get (10) | 80K ops/sec | 12ms | 25ms |
Memory efficiency:
- 50-90% reduction in Redis memory usage with compression
- ~12KB per million unique keys with HyperLogLog analytics
- Bounded memory for access tracking with Redis Streams
| Feature | Rustash | cached | redis-rs | moka |
|---|---|---|---|---|
| Multi-tier cache | β | β | β | β |
| Redis Streams analytics | β | β | β | β |
| Compression | β | β | β | β |
| Cache warming | β | β | β | β |
| OpenTelemetry | β | β | β | β |
| Type-safe API | β | β | β | β |
| Production features | β | β | β |
- Rust: 1.70+
- Redis: 6.0+ (Redis 7.0+ recommended for all features)
- Tokio: 1.0+ async runtime
Optional:
- OpenTelemetry collector for metrics
- Jaeger/Prometheus for observability
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT License (LICENSE-MIT)
at your option.
Contributions are welcome! Please read our Contributing Guide and check out Good First Issues.
- Redis Cluster support - Full cluster topology awareness
- Distributed locks - Redis-based distributed locking
- Pub/Sub integration - Cache invalidation via Redis pub/sub
- Grafana dashboards - Pre-built observability dashboards
- More serialization formats - MessagePack, CBOR support
- Edge caching - CDN-style cache hierarchies
Built with β€οΈ for the Rust community