Rust में कैशिंग: Redis, Memcached और अंतर्निहित समाधान (उन्नत स्तर)

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

परिचय: Rust में कैशिंग क्यों एक चुनौती और लाभ है

\n

Rust पर उच्च-लोड सिस्टम में, कैशिंग केवल एक लाइब्रेरी जोड़ने से कहीं अधिक हो जाती है। सख्त स्वामित्व प्रणाली, गार्बेज कलेक्टर की अनुपस्थिति और थ्रेड-सुरक्षा आवश्यकताओं के कारण, पारंपरिक दृष्टिकोणों पर पुनर्विचार करने की आवश्यकता है। हालाँकि, Rust अद्वितीय क्षमताएँ प्रदान करता है: पूर्वानुमानित प्रतिक्रिया समय, GC पर शून्य ओवरहेड और मेमोरी पर पूर्ण नियंत्रण। इस लेख में, हम कैशिंग की उन्नत तकनीकों पर चर्चा करेंगे: वितरित समाधानों (Redis, Memcached) से लेकर अंतर्निहित कैश (moka, lru) और उनके संयोजन तक।

\n\n

1. deadpool-redis के माध्यम से Redis के साथ अतुल्यकालिक कार्य

\n

1.1. सीधे redis-rs क्यों नहीं?

\n

क्लाइंट redis-rs सिंक्रोनस है। tokio पर अतुल्यकालिक अनुप्रयोगों के लिए कनेक्शन पूल की आवश्यकता होती है। deadpool-redis एक अतुल्यकालिक पूल प्रदान करता है जो कनेक्शन का प्रबंधन करता है और विफलताओं पर स्वचालित रूप से पुनः कनेक्ट होता है।

\n\n

1.2. उदाहरण: TTL और सीरियलाइज़ेशन के साथ कैशिंग

\n
use deadpool_redis::{Config, Runtime, Pool};\nuse serde::{Serialize, Deserialize};\nuse tokio::sync::OnceCell;\n\n#[derive(Serialize, Deserialize, Clone)]\nstruct User {\n    id: u64,\n    name: String,\n    email: String,\n}\n\nasync fn get_pool() -> Pool {\n    static POOL: OnceCell<Pool> = OnceCell::const_new();\n    POOL.get_or_init(|| async {\n        let cfg = Config::from_url("redis://127.0.0.1/");\n        cfg.create_pool(Some(Runtime::Tokio1)).unwrap()\n    }).await.clone()\n}\n\nasync fn get_user_cached(user_id: u64) -> Option<User> {\n    let pool = get_pool().await;\n    let mut conn = pool.get().await.unwrap();\n    let key = format!("user:{}", user_id);\n\n    // कैश से पढ़ने का प्रयास\n    if let Ok(Some(data)) = redis::cmd("GET").arg(&key).query_async::<Option<Vec<u8>>>(&mut conn).await {\n        if let Ok(user) = bincode::deserialize::<User>(&data) {\n            return Some(user);\n        }\n    }\n    None\n}\n\nasync fn set_user_cache(user: &User) {\n    let pool = get_pool().await;\n    let mut conn = pool.get().await.unwrap();\n    let key = format!("user:{}", user.id);\n    let data = bincode::serialize(user).unwrap();\n\n    // TTL 300 सेकंड\n    let _: () = redis::cmd("SETEX")\n        .arg(&key)\n        .arg(300)\n        .arg(&data)\n        .query_async(&mut conn)\n        .await\n        .unwrap();\n}
\n\n

1.3. उन्नत रणनीति: लॉक के साथ Cache-Aside

\n

cache stampede (जब कई अनुरोध एक साथ कैश को फिर से भरने का प्रयास करते हैं) के मामले में, एप्लिकेशन स्तर पर म्यूटेक्स का उपयोग करें:

\n
use tokio::sync::Mutex;\nuse std::collections::HashMap;\n\nstruct CacheLock {\n    locks: Mutex<HashMap<String, tokio::sync::Semaphore>>,\n}\n\nimpl CacheLock {\n    async fn get_or_compute<F, Fut, T>(&self, key: &str, f: F) -> T\n    where\n        F: FnOnce() -> Fut,\n        Fut: Future<Output = T>,\n    {\n        let sem = {\n            let mut map = self.locks.lock().await;\n            map.entry(key.to_string())\n                .or_insert_with(|| tokio::sync::Semaphore::new(1))\n                .clone()\n        };\n        let _permit = sem.acquire().await.unwrap();\n        f().await\n    }\n}
\n\n

2. Memcached: memcache-async के साथ हल्कापन और गति

\n

2.1. Rust के लिए Memcached की विशेषताएँ

\n

Memcached Redis से सरल है: इसमें कोई स्थायित्व या जटिल डेटा संरचनाएँ नहीं हैं, लेकिन यह सरल key-value संचालन के लिए तेज़ है। क्रेट memcache-async tokio पर एक अतुल्यकालिक क्लाइंट प्रदान करता है।

\n\n

2.2. उदाहरण: बैच लोडिंग और पाइपलाइनिंग

\n
use memcache_async::{Client, Protocol, Value};\nuse bytes::Bytes;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let client = Client::connect_async("memcache://127.0.0.1:11211").await?;\n\n    // प                

ब्लॉग

पुस्तक अनुशंसाएँ