التخزين المؤقت في Rust: Redis وMemcached والحلول المدمجة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

التخزين المؤقت في Rust: Redis وMemcached والحلول المدمجة



التخزين المؤقت هو أحد الآليات الرئيسية لتحسين أداء التطبيقات الحديثة. في نظام Rust البيئي، المعروف بسرعته وأمان الذاكرة، يمكن أن يؤثر اختيار الأداة المناسبة للتخزين المؤقت بشكل كبير على كفاءة البرنامج. في هذه المقالة، سننظر في ثلاثة أساليب رئيسية: الأنظمة الخارجية Redis وMemcached، بالإضافة إلى الحلول المدمجة المتوفرة في المكتبة القياسية والـ crates الشائعة.



لماذا التخزين المؤقت في Rust؟

Rust بحد ذاته سريع جدًا، ولكن عند العمل مع قواعد البيانات، أو واجهات برمجة التطبيقات الخارجية (APIs)، أو العمليات الحسابية المعقدة، يسمح التخزين المؤقت بـ:

  • تقليل زمن الاستجابة (latency) عند الطلبات المتكررة
  • تقليل الحمل على قواعد البيانات والخدمات الخارجية
  • توفير الموارد الحاسوبية ووقت المعالج (CPU)


1. الحلول المدمجة: HashMap وLRU-cache

أبسط طريقة للتخزين المؤقت في Rust هي استخدام HashMap من المكتبة القياسية. للتطبيقات متعددة الخيوط، ستحتاج إلى غلاف Mutex<HashMap> أو RwLock<HashMap>. ومع ذلك، فإن هذا الأسلوب لا يحتوي على سياسة إخلاء (eviction policy)، مما قد يؤدي إلى نمو غير محدود للذاكرة.



مثال على cache بسيط باستخدام HashMap

use std::collections::HashMap;use std::sync::Mutex;

struct SimpleCache { store: Mutex<HashMap<String, String>>,}

impl SimpleCache { fn new() -> Self { SimpleCache { store: Mutex::new(HashMap::new()), } }

fn get(&self, key: &str) -> Option<String> { self.store.lock().unwrap().get(key).cloned() }

fn set(&self, key: String, value: String) { self.store.lock().unwrap().insert(key, value); }}


LRU-cache عبر crate lru

لتحديد حجم cache والإخلاء التلقائي للإدخالات القديمة، استخدم crate lru. وهو يطبق خوارزمية Least Recently Used — حيث يقوم بحذف العناصر الأقل استخدامًا.



use lru::LruCache;use std::num::NonZeroUsize;

fn main() { let mut cache = LruCache::new(NonZeroUsize::new(3).unwrap()); cache.put("apple", 10); cache.put("banana", 20); cache.put("cherry", 30); cache.put("date", 40); // "apple" سيتم إخلاؤه

println!("{:?}", cache.get(&"apple")); // None println!("{:?}", cache.get(&"date")); // Some(40)}


الإيجابيات: زمن استجابة شبكة صفري، بساطة، تحكم كامل. السلبيات: cache يعيش فقط ضمن عملية واحدة، لا يوجد استمرارية (persistence).



2. التخزين المؤقت مع Redis عبر redis-rs

Redis هو مخزن قيم-مفاتيح في الذاكرة (in-memory)، يُستخدم غالبًا كـ cache موزع. في Rust، يتم استخدام crate redis (أو redis-rs) للعمل مع Redis.



الاتصال والعمل الأساسي

use redis::Commands;

fn main() -> redis::RedisResult<()> { let client = redis::Client::open("redis://127.0.0.1:6379/")?; let mut con = client.get_connection()?;

// تعيين قيمة مع TTL (وقت الحياة) con.set_ex("user:42", "{\\"name\\": \\"Alice\\"}", 60)?;

// القراءة let value: String = con.get("user:42")?; println!("{}", value);

// التحقق من الوجود let exists: bool = con.exists("user:42")?; println!("Exists: {}", exists);

Ok(())}


الإمكانيات المتقدمة لـ Redis

  • TTL (Time To Live): الحذف التلقائي للإدخالات القديمة
  • هياكل البيانات: القوائم، المجموعات، التجزئات — لسيناريوهات معقدة
  • Pub/Sub: إشعارات بتغييرات cache
  • التجميع (Clustering): التوسع الأفقي


الإيجابيات: موزع

المدونات

توصيات الكتب