রেডিস ব্যবহারের ক্ষেত্র: ক্যাশিং, কিউ এবং রেট লিমিটিং
আপনি একটি ওয়েব অ্যাপ তৈরি করেছেন যা কয়েকজন ব্যবহারকারীর সাথে ঠিকঠাক কাজ করে, কিন্তু ট্রাফিক বাড়ার সাথে সাথে আপনি ধীর পেজ লোড, ডুপ্লিকেট ব্যাকগ্রাউন্ড জব এবং অপব্যবহারকারী ক্লায়েন্টদের দ্বারা API-তে আঘাত লক্ষ্য করেন। এগুলি ক্লাসিক স্কেলিং সমস্যা যা রেডিস সুন্দরভাবে সমাধান করতে পারে। রেডিস একটি ইন-মেমরি ডেটা স্টোর যা তিনটি মূল কাজে দক্ষ: ক্যাশিং, কিউ এবং রেট লিমিটিং। এই নিবন্ধে, আমরা প্রতিটি ব্যবহারের ক্ষেত্র ব্যবহারিক উদাহরণ এবং সেরা অনুশীলন সহ অন্বেষণ করব।
এই ব্যবহারের ক্ষেত্রে রেডিস কেন?
রেডিস ডেটা মেমরিতে সংরক্ষণ করে, যা এটিকে অবিশ্বাস্যভাবে দ্রুত করে তোলে—প্রায়শই সাব-মিলিসেকেন্ড প্রতিক্রিয়া সময়। এটি স্ট্রিং, লিস্ট, সেট, সর্টেড সেট এবং হ্যাশের মতো সমৃদ্ধ ডেটা স্ট্রাকচার সমর্থন করে, যা স্বাভাবিকভাবেই ক্যাশিং, কিউ এবং রেট লিমিটিং-এ ম্যাপ করে। এটি অ্যাটমিক অপারেশন, পাব/সাব এবং পার্সিস্টেন্স অপশনও অফার করে, যা এটিকে ব্যাকএন্ড ডেভেলপারদের জন্য একটি বহুমুখী হাতিয়ার করে তোলে।
১. রেডিস দিয়ে ক্যাশিং
ক্যাশিং হল সবচেয়ে সাধারণ রেডিস ব্যবহারের ক্ষেত্র। ঘন ঘন অ্যাক্সেস করা ডেটা রেডিসে সংরক্ষণ করে, আপনি ডেটাবেস লোড কমিয়ে প্রতিক্রিয়া দ্রুততর করতে পারেন।
ক্যাশিং কীভাবে কাজ করে
যখন একটি অনুরোধ আসে, তখন পরীক্ষা করুন ডেটা রেডিসে আছে কিনা। যদি থাকে (ক্যাশ হিট), সরাসরি ফেরত দিন। যদি না থাকে (ক্যাশ মিস), ডেটাবেস থেকে আনুন, একটি এক্সপায়ারেশন সময় সহ রেডিসে সংরক্ষণ করুন এবং ফেরত দিন। এই প্যাটার্নটিকে ক্যাশ-অ্যাডসাইড বলা হয়।
// Node.js উদাহরণ ioredis ব্যবহার করে
const Redis = require('ioredis');
const redis = new Redis();
async function getUser(userId) {
const cacheKey = `user:${userId}`;
const cached = await redis.get(cacheKey);
if (cached) return JSON.parse(cached);
const user = await db.query('SELECT * FROM users WHERE id = ?', [userId]);
await redis.set(cacheKey, JSON.stringify(user), 'EX', 3600); // 1 ঘন্টা TTL
return user;
}
ক্যাশিংয়ের জন্য সেরা অনুশীলন
- একটি TTL সেট করুন: পুরানো ডেটা এবং মেমরি ব্লোট এড়াতে সর্বদা একটি এক্সপায়ারেশন সময় সেট করুন।
- উপযুক্ত ডেটা স্ট্রাকচার ব্যবহার করুন: সাধারণ কী-ভ্যালুর জন্য, স্ট্রিং ব্যবহার করুন। অবজেক্টের জন্য, পৃথকভাবে ফিল্ড আপডেট করতে হ্যাশ ব্যবহার করুন।
- ক্যাশ ইনভ্যালিডেশন পরিচালনা করুন: অন্তর্নিহিত ডেটা পরিবর্তিত হলে ক্যাশ এন্ট্রি আপডেট বা মুছে ফেলুন।
- হিট রেট মনিটর করুন: একটি কম হিট রেট মানে আপনার ক্যাশ কার্যকর নয়; কী বা TTL সমন্বয় করুন।
ক্যাশ ইনভ্যালিডেশন কৌশল
ইনভ্যালিডেশন কঠিন। সাধারণ কৌশলগুলির মধ্যে রয়েছে:
- সময়-ভিত্তিক: TTL-এর উপর নির্ভর করুন। সহজ কিন্তু পুরানো ডেটা পরিবেশন করতে পারে।
- রাইট-থ্রু: আপনি যখনই ডেটাবেস আপডেট করেন তখনই ক্যাশ আপডেট করুন।
- রাইট-বিহাইন্ড: প্রথমে ক্যাশ আপডেট করুন, তারপর অসিঙ্ক্রোনাসভাবে ডেটাবেস আপডেট করুন (ডেটা হারানোর ঝুঁকি)।
২. রেডিস দিয়ে কিউ
কিউ সময়সাপেক্ষ কাজগুলিকে অনুরোধ-প্রতিক্রিয়া চক্র থেকে আলাদা করে। উদাহরণস্বরূপ, ইমেল পাঠানো, ছবি প্রক্রিয়াকরণ বা রিপোর্ট তৈরি অসিঙ্ক্রোনাসভাবে করা যেতে পারে।
একটি সাধারণ কিউ বাস্তবায়ন
রেডিস লিস্ট কিউ-এর জন্য নিখুঁত। বাম দিকে জব যোগ করতে LPUSH ব্যবহার করুন এবং ডান দিক থেকে ব্লক এবং পপ করতে BRPOP ব্যবহার করুন (FIFO)।
// প্রোডিউসার: জব যোগ করুন
await redis.lpush('email_queue', JSON.stringify({ to: 'user@example.com', subject: 'Welcome' }));
// কনজিউমার: জব প্রসেস করুন (একটি ওয়ার্কারে)
while (true) {
const job = await redis.brpop('email_queue', 0); // 0 = অনির্দিষ্টকালের জন্য ব্লক
const { to, subject } = JSON.parse(job[1]);
await sendEmail(to, subject);
}
BRPOPLPUSH দিয়ে নির্ভরযোগ্য কিউ
একজন ওয়ার্কার ক্র্যাশ করলে জব হারানো এড়াতে, BRPOPLPUSH ব্যবহার করে অ্যাটমিকভাবে জবটিকে একটি প্রসেসিং লিস্টে সরান। সফল প্রসেসিংয়ের পরে, এটি প্রসেসিং লিস্ট থেকে সরান। যদি ওয়ার্কার মারা যায়, অন্য একজন ওয়ার্কার প্রসেসিং লিস্ট থেকে জব পুনরুদ্ধার করতে পারে।
const job = await redis.brpoplpush('email_queue', 'processing_queue', 0);
try {
// জব প্রসেস করুন
await redis.lrem('processing_queue', 1, job);
} catch (err) {
// ত্রুটি পরিচালনা করুন, হয়তো পুনরায় কিউতে যোগ করুন
}
ডেডিকেটেড কিউ লাইব্রেরি
প্রোডাকশনের জন্য, Bull (Node.js), RQ (Python), বা Sidekiq (Ruby) এর মতো লাইব্রেরি বিবেচনা করুন। তারা রিট্রাই, শিডিউলিং এবং মনিটরিং সরবরাহ করে।
৩. রেডিস দিয়ে রেট লিমিটিং
রেট লিমিটিং আপনার API-কে অপব্যবহার থেকে রক্ষা করে এবং ন্যায্য ব্যবহার নিশ্চিত করে। রেডিসের অ্যাটমিক অপারেশনগুলি অনুরোধ গণনার জন্য এটিকে আদর্শ করে তোলে।
ফিক্সড উইন্ডো রেট লিমিটিং
প্রতি ব্যবহারকারীর জন্য প্রতি সময় উইন্ডোতে একটি কাউন্টার বাড়ান। যদি গণনা সীমা ছাড়িয়ে যায়, অনুরোধ প্রত্যাখ্যান করুন।
async function isAllowed(userId, limit = 100, windowSec = 60) {
const key = `rate:${userId}:${Math.floor(Date.now() / 1000 / windowSec)}`;
const count = await redis.incr(key);
if (count === 1) await redis.expire(key, windowSec);
return count