استخدامات Redis: التخزين المؤقت وقوائم الانتظار وتحديد المعدل

Backend2026-10-06TryQuickToolBox

لقد قمت ببناء تطبيق ويب يعمل بشكل جيد مع عدد قليل من المستخدمين، ولكن مع نمو حركة المرور، تلاحظ بطء تحميل الصفحات، وتكرار المهام في الخلفية، وتعرض واجهات برمجة التطبيقات (APIs) لهجمات من عملاء مسيئين. هذه مشكلات توسع كلاسيكية يمكن لـ Redis حلها بأناقة. Redis هو مخزن بيانات في الذاكرة يتميز في ثلاث مهام أساسية: التخزين المؤقت، وقوائم الانتظار، وتحديد المعدل. في هذه المقالة، سنستكشف كل حالة استخدام مع أمثلة عملية وأفضل الممارسات.

لماذا Redis لهذه الاستخدامات؟

يخزن Redis البيانات في الذاكرة، مما يجعله سريعًا بشكل لا يصدق - غالبًا بأوقات استجابة أقل من مللي ثانية. يدعم هياكل بيانات غنية مثل السلاسل النصية، والقوائم، والمجموعات، والمجموعات المرتبة، والتجزئات (hashes)، والتي تتوافق بشكل طبيعي مع التخزين المؤقت وقوائم الانتظار وتحديد المعدل. كما يوفر عمليات ذرية (atomic)، ونظام النشر/الاشتراك (pub/sub)، وخيارات الاستمرارية، مما يجعله أداة متعددة الاستخدامات لمطوري الواجهة الخلفية.

1. التخزين المؤقت باستخدام Redis

التخزين المؤقت هو حالة الاستخدام الأكثر شيوعًا لـ Redis. من خلال تخزين البيانات التي يتم الوصول إليها بشكل متكرر في Redis، تقلل من حمل قاعدة البيانات وتسرع الاستجابات.

كيف يعمل التخزين المؤقت

عند وصول طلب، تحقق مما إذا كانت البيانات موجودة في Redis. إذا كانت موجودة (إصابة ذاكرة التخزين المؤقت)، فأعدها مباشرة. إذا لم تكن موجودة (فشل ذاكرة التخزين المؤقت)، فاجلبها من قاعدة البيانات، وخزّنها في Redis مع وقت انتهاء الصلاحية، ثم أعدها. يُسمى هذا النمط بالتخزين المؤقت الجانبي (cache-aside).

// Node.js example using 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 hour TTL
  return user;
}

أفضل الممارسات للتخزين المؤقت

استراتيجيات إبطال ذاكرة التخزين المؤقت

الإبطال صعب. تشمل الاستراتيجيات الشائعة:

2. قوائم الانتظار باستخدام Redis

تفصل قوائم الانتظار المهام التي تستغرق وقتًا طويلاً عن دورة الطلب والاستجابة. على سبيل المثال، يمكن إرسال البريد الإلكتروني، أو معالجة الصور، أو إنشاء التقارير بشكل غير متزامن.

تنفيذ قائمة انتظار بسيطة

قوائم Redis مثالية لقوائم الانتظار. استخدم LPUSH لإضافة المهام إلى اليسار و BRPOP للحظر والانتظار حتى تظهر من اليمين (FIFO).

// Producer: add job
await redis.lpush('email_queue', JSON.stringify({ to: 'user@example.com', subject: 'Welcome' }));

// Consumer: process job (in a worker)
while (true) {
  const job = await redis.brpop('email_queue', 0); // 0 = block indefinitely
  const { to, subject } = JSON.parse(job[1]);
  await sendEmail(to, subject);
}

قوائم انتظار موثوقة باستخدام BRPOPLPUSH

لتجنب فقدان المهام إذا تعطل عامل، استخدم BRPOPLPUSH لنقل المهمة بشكل ذري إلى قائمة المعالجة. بعد المعالجة الناجحة، قم بإزالتها من قائمة المعالجة. إذا مات العامل، يمكن لعامل آخر استرداد المهام من قائمة المعالجة.

const job = await redis.brpoplpush('email_queue', 'processing_queue', 0);
try {
  // process job
  await redis.lrem('processing_queue', 1, job);
} catch (err) {
  // handle error, maybe requeue
}

مكتبات قوائم الانتظار المخصصة

للإنتاج، فكر في مكتبات مثل Bull (Node.js)، أو RQ (Python)، أو Sidekiq (Ruby). فهي توفر إعادة المحاولات والجدولة والمراقبة جاهزة.

3. تحديد المعدل باستخدام Redis

يحمي تحديد المعدل واجهة برمجة التطبيقات الخاصة بك من الإساءة ويضمن الاستخدام العادل. تجعل العمليات الذرية لـ Redis مثاليًا لحساب الطلبات.

تحديد المعدل بنافذة ثابتة

قم بزيادة عداد لكل مستخدم لكل نافذة زمنية. إذا تجاوز العدد الحد المسموح، ارفض الطلب.

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