الرئيسيةمن أناالدوراتالمدونةسوق الأوامرالمناهج والباقاتالشركاء

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

المنصة مبنية على الوضوح، التطبيق، والنتيجة النافعة: شرح مرتب يساعدك تفهم الأدوات، تكتب كودًا أفضل، وتستخدم الذكاء الاصطناعي بوعي داخل العمل الحقيقي.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • المناهج والباقات
  • سوق الأوامر
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالمناهجالمدونةالدخول
How To Make It

اعمل طبقة كاش بـ Redis في Node.js: نزّل زمن الاستجابة من 820 لـ 5 مللي ثانية

مبتدئ1 أغسطس 20265 دقائق قراءة
اعمل طبقة كاش بـ Redis في Node.js: نزّل زمن الاستجابة من 820 لـ 5 مللي ثانية

المستوى: مبتدئ. هذا الدليل يفترض إنك تعرف تكتب دالة بسيطة في Node.js وتشغّل query على PostgreSQL، ومش لازم تكون جرّبت Redis قبل كده.

لو نفس صفحة المنتج في موقعك بترجع لكل زائر من قاعدة البيانات، وبتاخد قرب الثانية، انت بتكرّر شغل تقدر تعمله مرة واحدة. في آخر الدليل هيبقى عندك دالة قراءة بترجع في حوالي 5 مللي ثانية بدل 820، بكود تقدر تنسخه دلوقتي.

ابنِ طبقة كاش بـ Redis أمام قاعدة بياناتك في Node.js

المشكلة باختصار

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

شعار فيل PostgreSQL قاعدة البيانات الأساسية اللي بنخفف الحمل عنها بطبقة الكاش

الفكرة بمثال بسيط، ثم علميًا

تخيّل مكتبك. الورقة اللي بتحتاجها كل شوية بتحطها في درج المكتب اللي قدامك، توصلها في ثانية. الأوراق النادرة بتفضل في الأرشيف في الدور التحت، لو احتجت واحدة بتنزل تجيبها. مبتنقلش الأرشيف كله فوق، وبرضه مبتنزلش الأرشيف في كل مرة.

علميًا: الدرج ده اسمه الكاش (cache)، و Redis قاعدة بيانات بتخزّن المفاتيح والقيم في الذاكرة (RAM) بدل القرص، فالقراءة منها بتتقاس بالمللي ثانية. النمط اللي بنستخدمه اسمه cache-aside (أو lazy loading): التطبيق بيسأل الكاش الأول، ولو ملقاش (miss) بيروح لقاعدة البيانات مرة واحدة، وبعدين يخزّن النتيجة في الكاش عشان الطلب الجاي يبقى hit.

الخطوات

  1. شغّل Redis وركّب المكتبات. أسرع طريقة محليًا هي حاوية Docker.
  2. اعمل اتصال واحد لكل من Redis و PostgreSQL على مستوى التطبيق، مش لكل طلب.
  3. اقرأ بنمط cache-aside: اسأل Redis، لو hit رجّع فورًا، لو miss اقرأ من الداتابيز وخزّن.
  4. حُط مهلة صلاحية (TTL) على كل مفتاح عشان الداتا متبقاش قديمة للأبد.
  5. أبطِل الكاش عند التعديل: امسح المفتاح مع أي UPDATE عشان القراءة الجاية تجيب الجديد.
  6. قِس الفرق بأداة حِمل بسيطة قبل وبعد.

1) التشغيل والتركيب

Bash
# شغّل Redis 7 في ثوانٍ
docker run -d --name redis -p 6379:6379 redis:7

# مكتبتين فقط: عميل Redis وعميل PostgreSQL
npm install ioredis pg
شعار Node.js البيئة اللي بنكتب فيها دالة القراءة بنمط cache-aside

2) و 3) الاتصال ودالة القراءة (cache-aside)

JavaScript
import Redis from "ioredis";
import { Pool } from "pg";

const redis = new Redis();   // بيتصل بـ localhost:6379 افتراضيًا
const db = new Pool();       // بياخد إعدادات PostgreSQL من متغيرات البيئة

async function getProduct(id) {
  const key = `product:${id}`;

  // 1) دوّر في الكاش الأول
  const cached = await redis.get(key);
  if (cached) return JSON.parse(cached);   // HIT: رجّعنا في ~5ms من الذاكرة

  // 2) MISS: اقرأ من قاعدة البيانات مرة واحدة بس
  const { rows } = await db.query(
    "SELECT id, name, price FROM products WHERE id = $1",
    [id]
  );
  const product = rows[0];
  if (!product) return null;

  // 3) خزّنه في Redis بمهلة صلاحية 300 ثانية
  await redis.set(key, JSON.stringify(product), "EX", 300);
  return product;
}

ركّز في سطر set(... "EX", 300): ده اللي بيخلّي المفتاح يعيش 5 دقائق بس ثم يختفي لوحده. من غيره الكاش هيمتلئ ويحتفظ ببيانات قديمة.

4) و 5) الصلاحية وإبطال الكاش عند التعديل

الافتراض إن سعر المنتج بيتغيّر أحيانًا. لو غيّرته في الداتابيز بس، الكاش هيفضل يرجّع السعر القديم لحد ما الـ TTL يخلص. عشان كده امسح المفتاح مع كل تعديل:

JavaScript
async function updateProductPrice(id, newPrice) {
  await db.query("UPDATE products SET price = $1 WHERE id = $2", [newPrice, id]);
  await redis.del(`product:${id}`);   // القراءة الجاية هتعمل MISS وتجيب الجديد
}

6) قِس الفرق بنفسك

Bash
npx autocannon -c 50 -d 10 http://localhost:3000/products/42

على جدول فيه 10 آلاف منتج وبدون فهرس مناسب، أول طلب (MISS) ممكن ياخد حوالي 820 مللي ثانية. كل طلب بعده على نفس المنتج (HIT) بيرجع في حوالي 5 مللي ثانية، أي أسرع بحوالي 160 مرة. لو 90% من الطلبات hits، متوسط زمن الاستجابة بينزل بشكل واضح، والحمل على PostgreSQL بيقل لأن أغلب القراءات مبتوصلوش له أصلًا.

الـ trade-offs: بتكسب إيه وبتخسر إيه

  • بتكسب: سرعة قراءة بالمللي ثانية، وحمل أقل بكتير على قاعدة البيانات.
  • بتخسر: احتمال إن البيانات تبقى قديمة (stale) لمدة الـ TTL — 300 ثانية في مثالنا — لو نسيت تبطّل الكاش. وكمان ذاكرة زيادة: 10 آلاف منتج بحجم ~1 كيلوبايت للواحد يعني حوالي 10 ميجابايت في Redis.
  • الافتراض هنا إن القراءة أكتر بكتير من الكتابة، وإن تأخير بسيط في تحديث البيانات مقبول. لو ده مش وضعك، الكاش ممكن يعملك مشاكل أكتر مما يحل.

متى لا تستخدم هذه الطريقة

  • بيانات لازم تكون دقيقة 100% في كل لحظة، زي رصيد بنكي أو كمية مخزون وقت الشراء. الـ stale هنا خطر حقيقي.
  • بيانات بتتقري مرة واحدة ومبتتكررش. الكاش بيفيد مع التكرار؛ من غير تكرار انت بتضيف تعقيد بدون مكسب.
  • الاستعلام أصلًا سريع (أقل من 10 مللي ثانية) لأن عندك فهرس كويس. ساعتها ابدأ بالفهرس، مش بالكاش.

التحقق من أنه يعمل

افتح redis-cli وشغّل MONITOR، وانت بتطلب نفس المنتج مرتين. المرة الأولى هتشوف GET يليه SET (miss ثم تخزين)، والمرة التانية هتشوف GET بس (hit). لو شفت SET في كل مرة، يبقى في مشكلة في المفتاح أو الـ TTL.

الخطوة التالية

خُد أبطأ endpoint قراءة عندك دلوقتي، لفّه بدالة getProduct اللي فوق، وشغّل autocannon عليه قبل وبعد. لو الزمن نزل بشكل واضح والحمل على الداتابيز قلّ، الكاش شغّال صح؛ ابدأ بالمفتاح الأكثر طلبًا وبس.

المصادر

  • توثيق أمر SET وخيار EX في Redis: redis.io/docs/latest/commands/set
  • أنماط الكاش (cache-aside / lazy loading) — AWS ElastiCache: docs.aws.amazon.com
  • عميل ioredis الرسمي: github.com/redis/ioredis
  • عميل node-postgres (pg): node-postgres.com
  • أداة قياس الحِمل autocannon: github.com/mcollina/autocannon

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة