مقدمة في التخزين المؤقت في Rust
التخزين المؤقت هو أحد الأدوات الرئيسية لتحسين أداء التطبيقات في Rust. سواء كنت تقوم ببناء خادم ويب عالي التحميل، أو قاعدة بيانات، أو تطبيق سطح مكتب، فإن التخزين المؤقت الجيد يسمح بتقليل وقت الاستجابة، وتخفيف الحمل على الموارد الخارجية، وتحسين استخدام الذاكرة. في هذه المقالة، سنستعرض ثلاثة أساليب رئيسية للتخزين المؤقت في نظام Rust البيئي: استخدام الأنظمة الخارجية (Redis وMemcached) والحلول المدمجة مثل lru-rs وmoka. ستتعرف على متى تختار أي أداة، وستحصل على أمثلة جاهزة للكود.
أنظمة التخزين المؤقت الخارجية: Redis وMemcached
التخزين المؤقت باستخدام Redis في Rust
Redis هو مخزن بيانات شائع في الذاكرة يدعم هياكل بيانات متنوعة (سلاسل، قوائم، مجموعات، جداول تجزئة). للعمل مع Redis في Rust، يتم استخدام الكريت redis (أو redis-rs).
نقوم بإضافة التبعية في Cargo.toml:
[dependencies]redis = { version = "0.25", features = ["tokio-comp"] }tokio = { version = "1", features = ["full"] }serde = { version = "1", features = ["derive"] }serde_json = "1"مثال على الاتصال والتخزين المؤقت الأساسي باستخدام Redis:
use redis::AsyncCommands;use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]struct User { id: u32, name: String, email: String,}
#[tokio::main]async fn main() -> redis::RedisResult<()> { let client = redis::Client::open("redis://127.0.0.1:6379/")?; let mut conn = client.get_multiplexed_async_connection().await?;
// حفظ كائن في الذاكرة المؤقتة (تسلسل إلى JSON) let user = User { id: 1, name: "أليكسي".into(), email: "alex@example.com".into(), }; let json = serde_json::to_string(&user).unwrap(); conn.set_ex("user:1", json, 3600).await?; // TTL = ساعة واحدة
// قراءة من الذاكرة المؤقتة let cached: String = conn.get("user:1").await?; let user_cached: User = serde_json::from_str(&cached).unwrap(); println!("تم الحصول على المستخدم: {:?}", user_cached);
Ok(())}مزايا Redis: دعم هياكل البيانات المعقدة، TTL، pub/sub، النسخ المتماثل، التجميع. العيوب: يتطلب خادماً منفصلاً، تأخيرات الشبكة.
التخزين المؤقت باستخدام Memcached في Rust
Memcached هو مخزن ذاكرة أخف وأبسط، يركز على تخزين أزواج "مفتاح-قيمة". بالنسبة لـ Rust، يتم استخدام الكريت memcache.
نضيف إلى Cargo.toml:
[dependencies]memcache = "0.19"tokio = { version = "1", features = ["full"] }مثال على العمل مع Memcached:
use memcache::Client;
#[tokio::main]async fn main() -> memcache::MemcacheResult<()> { let client = Client::connect("memcache://127.0.0.1:11211")?;
// كتابة مع TTL (بالثواني) client.set("greeting", "مرحباً بالعالم!", 300)?;
// قراءة let value: Option<String> = client.get("greeting")?; if let Some(msg) = value { println!("من الذاكرة المؤقتة: {}", msg); }
// زيادة العداد client.set("counter", "10", 0)?; client.increment("counter", 5)?; let counter: Option<u64> = client.get("counter")?; println!("العداد: {:?}", counter);
Ok(())}مزايا Memcached: البساطة، السرعة العالية، استهلاك ضئيل للذاكرة. العيوب: لا توجد هياكل بيانات معقدة، فقط تخزين سلاسل/بايتات.
الحلول المدمجة للتخزين المؤقت في Rust
مكتبة lru-rs (ذاكرة تخزين مؤقت LRU)
الكريت lru ينفذ خوارزمية الإزالة الكلاسيكية "الأقل استخداماً مؤخراً" (LRU). مثالي للتخزين المؤقت في الذاكرة