द्वारे तारिक एजाज
प्रदर्शन किसी भी सॉफ्टवेयर को डिजाइन करते समय विचार करने के लिए एक आवश्यक पैरामीटर है। यह विशेष रूप से महत्वपूर्ण है जब बात पर्दे के पीछे क्या होता है इसकी आती है।
हम, डेवलपर्स और टेक्नोलॉजिस्ट के रूप में, प्रदर्शन को बेहतर बनाने के लिए कई ट्विक्स और कार्यान्वयन अपनाते हैं। यहीं पर कैशिंग काम आती है।
कैशिंग को एक ऐसे तंत्र के रूप में परिभाषित किया गया है जो डेटा या फाइलों को एक अस्थायी स्टोरेज स्थान में स्टोर करता है जहां से जब भी आवश्यक हो इसे तुरंत एक्सेस किया जा सकता है।
कैशिंग आजकल वेब एप्लिकेशन में एक आवश्यक चीज बन गई है। हम Redis का उपयोग अपने वेब API को सुपरचार्ज करने के लिए कर सकते हैं - जो Node.js और MongoDB का उपयोग करके बनाए गए हैं।
"कैशिंग जाहिर तौर पर 100 से 200 साल बाद भी एक सुपर महत्वपूर्ण भूमिका निभाएगी।"
Redis: एक आम आदमी का अवलोकन
आधिकारिक डॉक्यूमेंटेशन के अनुसार, Redis को एक इन-मेमोरी डेटा स्ट्रक्चर स्टोर के रूप में परिभाषित किया गया है जिसका उपयोग डेटाबेस, मैसेज ब्रोकर, या कैश स्टोरेज के रूप में किया जाता है। यह स्ट्रिंग्स, हैश, लिस्ट्स, सेट्स, रेंज क्वेरी के साथ सॉर्टेड सेट्स, बिटमैप्स, हाइपरलॉगलॉग्स, रेडियस क्वेरी के साथ जियोस्पेशियल इंडेक्स और स्ट्रीम्स जैसे डेटा स्ट्रक्चर को सपोर्ट करता है।
ठीक है, यह वहां बहुत सारे डेटा स्ट्रक्चर हैं। बस इसे सरल बनाने के लिए, सपोर्टेड लगभग सभी डेटा स्ट्रक्चर को स्ट्रिंग के एक रूप या दूसरे में संघनित किया जा सकता है। जैसे-जैसे हम कार्यान्वयन के माध्यम से चलेंगे, आपको अधिक स्पष्टता मिलेगी।
लेकिन एक बात स्पष्ट है। Redis शक्तिशाली है, और जब सही ढंग से उपयोग किया जाता है तो यह हमारे एप्लिकेशन को न केवल तेज़ बल्कि आश्चर्यजनक रूप से कुशल बना सकता है। बहुत बातें हो गईं। आइए अपने हाथ गंदे करें।
आइए कोड की बात करें
शुरू करने से पहले, आपको अपने स्थानीय सिस्टम में Redis सेटअप प्राप्त करने की आवश्यकता होगी। आप Redis को चालू और चलाने के लिए इस त्वरित सेटअप प्रक्रिया का पालन कर सकते हैं।
हो गया? कूल। आइए शुरू करें। हमारे पास Express में बना एक सरल एप्लिकेशन है जो डेटा को पढ़ने और लिखने के लिए MongoDB Atlas में एक इंस्टेंस का उपयोग करता है।
हमारे पास /blogs रूट फाइल में दो प्रमुख API बने हैं।
...
// GET - आवश्यक यूजर के लिए सभी ब्लॉग पोस्ट लाता है
blogsRouter.route('/:user')
.get(async (req, res, next) => {
const blogs = await Blog.find({ user: req.params.user });
res.status(200).json({ blogs, });
});
// POST - एक नया ब्लॉग पोस्ट बनाता है
blogsRouter.route('/')
.post(async (req, res, next) => {
const existingBlog = await Blog.findOne({ title: req.body.title });
if (!existingBlog) {
let newBlog = new Blog(req.body);
const result = await newBlog.save();
return res.status(200).json({
message: `Blog ${result.id} is successfully created`,
result,
});
}
res.status(200).json({
message: 'Blog with same title exists',
});
});
...
कुछ Redis अच्छाई छिड़कें
हम npm पैकेज redis डाउनलोड करके शुरू करते हैं ताकि स्थानीय Redis सर्वर से कनेक्ट किया जा सके।
const mongoose = require('mongoose');
const redis = require('redis');
const util = require('util');
const redisUrl = 'redis://127.0.0.1:6379';
const client = redis.createClient(redisUrl);
client.hget = util.promisify(client.hget);
...
हम client.hget फंक्शन को कॉलबैक के बजाय एक प्रॉमिस लौटाने के लिए बदलने के लिए utils.promisify फंक्शन का उपयोग करते हैं। आप प्रोमिसिफिकेशन के बारे में यहां और पढ़ सकते हैं।
Redis कनेक्शन स्थापित है। इससे पहले कि हम कोई और कैशिंग कोड लिखना शुरू करें, आइए एक कदम पीछे हटें और यह समझने की कोशिश करें कि हमें किन आवश्यकताओं को पूरा करने की आवश्यकता है और संभावित चुनौतियों का सामना करना पड़ सकता है।
हमारी कैशिंग रणनीति निम्नलिखित बिंदुओं को संबोधित करने में सक्षम होनी चाहिए।
- किसी विशेष यूजर के लिए सभी ब्लॉग पोस्ट के लिए रिक्वेस्ट को कैश करें
हर बार एक नया ब्लॉग पोस्ट बनाए जाने पर कैश साफ़ करें
संभावित चुनौतियां जिनसे हमें सावधान रहना चाहिए जैसे ही हम अपनी रणनीति के बारे में जाते हैं:
कैश डेटा स्टोर करने के लिए की निर्माण को संभालने का सही तरीका
- कैश एक्सपायरी लॉजिक और कैश ताजगी बनाए रखने के लिए जबरन एक्सपायरी
- कैशिंग लॉजिक का पुन: प्रयोज्य कार्यान्वयन
ठीक है। हमारे पॉइंट्स नोट कर लिए गए हैं और Redis कनेक्टेड है। अगले चरण पर।
डिफ़ॉल्ट Mongoose Exec फंक्शन को ओवरराइड करना
हम चाहते हैं कि हमारा कैशिंग लॉजिक पुन: प्रयोज्य हो। और न केवल पुन: प्रयोज्य, हम यह भी चाहते हैं कि यह डेटाबेस पर कोई क्वेरी करने से पहले पहला चेकपॉइंट हो। यह mongoose exec फंक्शन पर पिगी-बैकिंग के एक साधारण हैक का उपयोग करके आसानी से किया जा सकता है।
...
const exec = mongoose.Query.prototype.exec;
...
mongoose.Query.prototype.exec = async function() {
...
const result = await exec.apply(this, arguments);
console.log('Data Source: Database');
return result;
}
...
हम मोंगूज के प्रोटोटाइप ऑब्जेक्ट का उपयोग करके अपने कैशिंग लॉजिक कोड को क्वेरी में पहले निष्पादन के रूप में जोड़ते हैं।
कैश को एक क्वेरी के रूप में जोड़ना
यह दर्शाने के लिए कि किन क्वेरी को कैशिंग के लिए तैयार किया जाना चाहिए, हम एक मोंगूज क्वेरी बनाते हैं। हम options ऑब्जेक्ट के माध्यम से हैश-की के रूप में उपयोग किए जाने वाले user को पास करने की क्षमता प्रदान करते हैं।
नोट: हैशकी एक हैश डेटा स्ट्रक्चर के लिए एक पहचानकर्ता के रूप में कार्य करता है जिसे सरल शब्दों में, एक सेट की-वैल्यू पेयर के पैरेंट की के रूप में कहा जा सकता है। जिससे, बड़ी संख्या में क्वेरी-वैल्यू सेट की कैशिंग सक्षम होती है। आप Redis में हैश के बारे में यहां और पढ़ सकते हैं।
...
mongoose.Query.prototype.cache = function(options = {}) {
this.enableCache = true;
this.hashKey = JSON.stringify(options.key || 'default');
return this;
};
...
ऐसा करने के बाद, हम उन क्वेरी के साथ cache(<options आर्गुमेंट>) क्वेरी का आसानी से उपयोग कर सकते हैं जिन्हें हम निम्न तरीके से कैश करना चाहते हैं।
...
const blogs = await Blog
.find({ user: req.params.user })
.cache({ key: req.params.user });
...
कैश लॉजिक तैयार करना
हमने यह दर्शाने के लिए एक सामान्य पुन: प्रयोज्य क्वेरी सेट की है कि किन क्वेरी को कैश करने की आवश्यकता है। आइए आगे बढ़ें और केंद्रीय कैशिंग लॉजिक लिखें।
...
mongoose.Query.prototype.exec = async function() {
if (!this.enableCache) {
console.log('Data Source: Database');
return exec.apply(this, arguments);
}
const key = JSON.stringify(Object.assign({}, this.getQuery(), {
collection: this.mongooseCollection.name,
}));
const cachedValue = await client.hget(this.hashKey, key);
if (cachedValue) {
const parsedCache = JSON.parse(cachedValue);
console.log('Data Source: Cache');
return Array.isArray(parsedCache) ? parsedCache.map(doc => new this.model(doc)) : new this.model(parsedCache);
}
const result = await exec.apply(this, arguments);
client.hmset(this.hashKey, key, JSON.stringify(result), 'EX', 300);
console.log('Data Source: Database');
return result;
};
...
जब भी हम अपने मुख्य क्वेरी के साथ cache() क्वेरी का उपयोग करते हैं, तो हम enableCache की को true पर सेट करते हैं।
यदि की गलत है, तो हम डिफ़ॉल्ट के रूप में मुख्य exec क्वेरी लौटाते हैं। यदि नहीं, तो हम पहले कैश डेटा को लाने और स्टोर/रिफ्रेश करने के लिए की बनाते हैं।
हम विशिष्टता के लिए डिफ़ॉल्ट क्वेरी के साथ collection नाम को की नाम के रूप में उपयोग करते हैं। उपयोग किया गया हैश-की user का नाम है जिसे हमने पहले cache() फंक्शन परिभाषा में पहले ही सेट कर दिया था।
कैश्ड डेटा को client.hget() फंक्शन का उपयोग करके प्राप्त किया जाता है जिसके लिए हैश-की और परिणामी की की आवश्यकता होती है।
नोट: हम Redis से कोई भी डेटा लाते समय हमेशा JSON.parse() का उपयोग करते हैं। और इसी तरह, हम Redis में कुछ भी स्टोर करने से पहले की और डेटा पर JSON.stringify() का उपयोग करते हैं। ऐसा इसलिए किया जाता है क्योंकि Redis JSON डेटा स्ट्रक्चर को सपोर्ट नहीं करता।
एक बार जब हमें कैश्ड डेटा मिल जाता है, तो हमें प्रत्येक कैश्ड ऑब्जेक्ट को एक मोंगूज मॉडल में बदलना होगा। यह बस new this.model(<object>) का उपयोग करके किया जा सकता है।
यदि कैश में आवश्यक डेटा नहीं है, तो हम डेटाबेस पर क्वेरी करते हैं। फिर, API को डेटा लौटाने के बाद, हम client.hmset() का उपयोग करके कैश को रिफ्रेश करते हैं। हम 300 सेकंड का डिफ़ॉल्ट कैश एक्सपायरी टाइम भी सेट करते हैं। यह आपकी कैशिंग रणनीति के आधार पर अनुकूलन योग्य है।
कैशिंग लॉजिक स्थापित है। हमने एक डिफ़ॉल्ट एक्सपायरी टाइम भी सेट किया है। अगला, हम जब भी एक नया ब्लॉग पोस्ट बनाया जाता है तो कैश एक्सपायरी को मजबूर करने पर गौर करते हैं।
जबरन कैश एक्सपायरी
कुछ मामलों में, जैसे जब कोई यूजर एक नया ब्लॉग पोस्ट बनाता है, तो यूजर उम्मीद करता है कि जब वे सभी पोस्ट लाएंगे तो नया पोस्ट उपलब्ध होना चाहिए।
ऐसा करने के लिए, हमें उस यूजर से संबंधित कैश को साफ़ करना होगा और इसे नए डेटा के साथ अपडेट करना होगा। इसलिए हमें जबरन एक्सपायरी करनी होगी। हम Redis द्वारा प्रदान किए गए del() फंक्शन को लागू करके ऐसा कर सकते हैं।
...
module.exports = {
clearCache(hashKey) {
console.log('Cache cleaned');
client.del(JSON.stringify(hashKey));
}
}
...
हमें यह भी ध्यान रखना होगा कि हम कई रूट्स पर एक्सपायरी को मजबूर करेंगे। एक विस्तार योग्य तरीका है इस clearCache() को मिडलवेयर के रूप में उपयोग करना और किसी भी रूट से संबंधित क्वेरी के निष्पादन समाप्त होने के बाद इसे एक बार कॉल करना।
const { clearCache } = require('../services/cache');
module.exports = async (req, res, next) => {
// रूट हैंडलर के समाप्त होने की प्रतीक्षा करें
await next();
clearCache(req.body.user);
}
इस मिडलवेयर को निम्न तरीके से किसी विशेष रूट पर आसानी से कॉल किया जा सकता है।
...
blogsRouter.route('/')
.post(cleanCache, async (req, res, next) => {
...
}
...
और हम हो गए। मैं सहमत हूं कि यह काफी सारा कोड था। लेकिन उस अंतिम भाग के साथ, हमने अपने एप्लिकेशन के साथ Redis सेट किया है और लगभग सभी संभावित चुनौतियों का ध्यान रखा है। अब हमारी कैशिंग रणनीति को एक्शन में देखने का समय है।
Redis एक्शन में
हम अपनी कैशिंग रणनीति को एक्शन में देखने के लिए Postman का उपयोग API क्लाइंट के रूप में करते हैं। यहां हम चलते हैं। आइए API ऑपरेशन्स को एक-एक करके चलाएं।
- हम
/blogsरूट का उपयोग करके एक नया ब्लॉग पोस्ट बनाते हैं
नया ब्लॉग पोस्ट निर्माण
- हम फिर यूजर
tejazसे संबंधित सभी ब्लॉग पोस्ट लाते हैं
यूजर tejaz के लिए सभी ब्लॉग पोस्ट लाना
- हम यूजर
tejazके लिए एक बार फिर सभी ब्लॉग पोस्ट लाते हैं।
यूजर tejaz के लिए एक बार फिर सभी ब्लॉग पोस्ट लाना
आप स्पष्ट रूप से देख सकते हैं कि जब हम कैश से लाते हैं, तो लिया गया समय 409ms से घटकर 24ms हो गया है। यह आपके API को लगभग 95% समय कम करके सुपरचार्ज करता है।
साथ ही, हम स्पष्ट रूप से देख सकते हैं कि कैश एक्सपायरी और अपडेट ऑपरेशन उम्मीद के मुताबिक काम करते हैं।
आप यहां redis-express फोल्डर में पूरा सोर्स कोड पा सकते हैं।
निष्कर्ष
किसी भी प्रदर्शन-कुशल और डेटा-गहन एप्लिकेशन के लिए कैशिंग एक अनिवार्य कदम है। Redis आपको इसे अपने वेब एप्लिकेशन में आसानी से प्राप्त करने में मदद करता है। यह एक सुपर शक्तिशाली टूल है, और यदि सही ढंग से उपयोग किया जाता है तो यह निश्चित रूप से डेवलपर्स के साथ-साथ यूजर्स को हर जगह एक उत्कृष्ट अनुभव प्रदान कर सकता है।
आप यहां Redis कमांड का पूरा सेट पा सकते हैं। आप इसका उपयोग redis-cli के साथ अपने कैश डेटा और एप्लिकेशन प्रोसेस की निगरानी के लिए कर सकते हैं।
किसी विशेष तकनीक द्वारा प्रदान की जाने वाली संभावनाएं वास्तव में अनंत हैं। यदि आपके कोई प्रश्न हैं, तो आप मुझसे LinkedIn पर संपर्क कर सकते हैं।
इस बीच, कोडिंग करते रहें।
मुफ़्त में कोड करना सीखें। freeCodeCamp का ओपन सोर्स पाठ्यक्रम 40,000 से अधिक लोगों को डेवलपर के रूप में नौकरी पाने में मदद कर चुका है। शुरू करें