Redis أم Memcached: أيهما لتخزينك المؤقت ولماذا
إذا كان كل ما تريده تخزيناً مؤقتاً بسيطاً لمفتاح وقيمة، فـMemcached يكفي وأخفّ. أما إذا احتجت قوائم وطوابير وpub/sub وثباتاً بعد إعادة التشغيل وبنى بيانات أغنى، فـRedis هو الجواب، وهو ما يختاره أغلب تطبيقات اليوم.
Redis وMemcached كلاهما مخزن بيانات في الذاكرة يسرّع تطبيقك بحفظ النتائج المتكررة بعيداً عن قاعدة البيانات البطيئة، لكن القرار بينهما يُحسم بسؤال واحد: هل تحتاج تخزيناً مؤقتاً بسيطاً فقط أم بنية بيانات أغنى؟ إذا كان كل ما تريده حفظ زوج مفتاح وقيمة نصّية (نتيجة استعلام، جزء صفحة، جلسة مستخدم)، فـMemcached يكفي، وهو أخفّ وأبسط ومتعدد الخيوط بطبيعته فيستغل عدة أنوية بكفاءة تحت حمل عالٍ متوازٍ. أما إذا احتجت أكثر من مفتاح وقيمة، مثل قوائم وطوابير مهام وpub/sub للأحداث الحيّة وترتيب متصدّرين (sorted sets) وعدّادات ذرّية، إضافةً إلى ثبات البيانات بعد إعادة تشغيل السيرفر بدل ضياعها، فـRedis هو الجواب الواضح. عملياً أغلب تطبيقات اليوم تختار Redis لأنه يفعل كل ما يفعله Memcached ويزيد عليه بنى بيانات وميزات لا يملكها الأخير، وبفارق أداء يسير في حالة التخزين البسيط. هذا المقال يضع جدول مقارنة صريحاً، ويشرح متى يكفي Memcached ومتى تحتاج قدرات Redis، وسياسات الإخلاء عند امتلاء الذاكرة، واستهلاك الرام على باقات كلاود بالأرقام.
جدول المقارنة الصريح
الفروق الجوهرية تتلخّص في الجدول التالي، وهو نقطة البداية لأي قرار:
| الخاصية | Redis | Memcached |
|---|---|---|
| أنواع البيانات | نصوص، قوائم، مجموعات، sorted sets، hashes، streams | مفتاح وقيمة نصّية فقط |
| الثبات على القرص | نعم (RDB وAOF) | لا، كل شيء يضيع بإعادة التشغيل |
| النسخ والتوسّع | نسخ متعدد وCluster مدمج | توزيع بسيط من جهة العميل |
| الخيوط | أحادي الخيط أساساً (مع I/O متعدد) | متعدد الخيوط |
| pub/sub والطوابير | نعم | لا |
| سياسات الإخلاء | ثماني سياسات دقيقة | LRU بسيط |
متى يكفي Memcached البسيط
Memcached مصمّم لهدف واحد يتقنه: تخزين مؤقت سريع وبسيط لأزواج مفتاح وقيمة. إذا كان استخدامك محصوراً في حفظ نتائج استعلامات ثقيلة أو أجزاء HTML مُصيّرة أو جلسات، وكان لديك حمل قراءة متوازٍ عالٍ جداً، فطبيعته متعددة الخيوط تعطيه أفضلية إذ يستغل كل أنوية المعالج بلا اختناق على خيط واحد. بساطته ميزة أيضاً: أقل إعدادات، أقل سطح للأخطاء، واستهلاك ذاكرة متوقّع. عيبه المقابل أن كل ما فيه يضيع لحظة إعادة تشغيل الخدمة أو السيرفر، لأنه لا يكتب شيئاً للقرص، فهو مناسب حصراً للبيانات التي يمكن إعادة بنائها بسهولة من المصدر. إذا كان فقدان الكاش مجرد إزعاج مؤقت (يُعاد ملؤه من قاعدة البيانات)، فهذا مقبول.
متى تحتاج قدرات Redis
Redis يتجاوز التخزين المؤقت إلى كونه أداة متعددة الأغراض. بنى بياناته تفتح استخدامات لا يقدر عليها Memcached: القوائم تصلح لطوابير مهام بسيطة (ادفع في طرف، اسحب من الآخر)، وsorted sets مثالية للوحات المتصدّرين والترتيب بالنقاط حيث كل عنصر مرتبط برقم ترتيب، وpub/sub يبثّ أحداثاً حيّة للمشتركين لحظياً (إشعارات، دردشة، تحديثات)، وhashes تخزّن كائناً كامل الحقول تحت مفتاح واحد، والعدّادات الذرّية ترفع رقماً بأمان تحت التزامن بلا تعارض. ميزة الثبات حاسمة أيضاً: مع RDB يأخذ Redis لقطة دورية للبيانات على القرص، ومع AOF يسجّل كل عملية كتابة، فتنجو بياناتك من إعادة التشغيل. لهذا يُستخدم Redis وسيطاً للطوابير في أطر مثل Laravel، ومخزناً للجلسات يبقى بعد النشر، وعدّاداً لمعدّلات الطلبات (rate limiting). إذا كان تطبيقك يحتاج أياً من هذه، فالقرار محسوم لصالح Redis.
نقطة الخيط الواحد
Redis أحادي الخيط في تنفيذ الأوامر، وهذا ليس عيباً كما يظن البعض بل تصميم مقصود يبسّط الذرّية ويلغي تعقيد الأقفال. عملياً يخدم Redis عشرات آلاف العمليات في الثانية على نواة واحدة لأن كل عملية سريعة جداً في الذاكرة. لكن معنى ذلك أن أمراً ثقيلاً واحداً (مثل KEYS على قاعدة ضخمة) يحجب كل الأوامر خلفه، فتجنّب الأوامر الماسحة الثقيلة في الإنتاج واستخدم بدائلها التدريجية. Memcached متعدد الخيوط يوزّع الحمل على الأنوية، وهي أفضليته الوحيدة الحقيقية في سيناريو القراءة البسيطة الكثيفة جداً.
سياسات الإخلاء عند امتلاء الذاكرة
كلاهما يعمل في الذاكرة المحدودة، فماذا يحدث حين تمتلئ؟ هنا يتفوّق Redis بمرونة سياسات الإخلاء. تضبط maxmemory بحدّ أقصى، ثم تختار سياسة عند بلوغه: allkeys-lru يحذف الأقل استخداماً حديثاً من كل المفاتيح، وهو الخيار الأشيع للكاش العام، وvolatile-lru يحذف الأقل استخداماً من المفاتيح ذات مهلة انتهاء فقط، وallkeys-lfu يعتمد على الأقل تكراراً في الاستخدام لا الأحدث، وnoeviction يرفض الكتابة الجديدة بدل حذف شيء (مناسب حين تكون البيانات ثمينة لا يجوز فقدها). Memcached يقدّم LRU بسيطاً وحيداً بلا هذا التنوّع. القاعدة العملية: اضبط maxmemory دائماً بحدّ واضح أقل من رام السيرفر المتاحة، فترك Redis بلا حدّ قد يجعله يلتهم كل الذاكرة ويُقتل من نظام التشغيل فجأة.
استهلاك الرام على باقات كلاود
التخزين في الذاكرة يعني أن الرام هي القيد الأول، فحجم الكاش محدود بما تخصّصه له. عملياً خدمة Redis أو Memcached خفيفة في استهلاكها الأساسي (عشرات الميغابايتات)، لكن حجم بياناتك المخزّنة هو ما يحدّد الاحتياج. على باقة خادم سحابي أساس بـ2GB رام، بعد نظام التشغيل وPHP وقاعدة البيانات، يبقى مجال معقول لكاش صغير إلى متوسط يكفي تطبيقاً في بداياته. مع نمو حجم الجلسات والكاش تحتاج رام أكثر، وإضافة 2GB في كلاود بـ600 ريال سنوياً بلا توقف الخدمة، أو ترقية لباقة نمو أو أعمال ذات الرام الأوسع. النصيحة: راقب استهلاك Redis بأمر INFO memory بانتظام، واضبط maxmemory على نحو 60% إلى 70% من الرام المتاحة تاركاً هامشاً لبقية الخدمات، فالكاش الذي يخنق سيرفرك ليس تسريعاً بل عبئاً.
مدة الصلاحية وإبطال الكاش
أياً كان اختيارك، الجزء الأصعب في التخزين المؤقت ليس الحفظ بل معرفة متى تُبطل القيمة المخزّنة. لكل مفتاح مدة صلاحية (TTL) تحدّد كم يبقى قبل أن يُحذف تلقائياً، وضبطها فن: مدة قصيرة جداً تُفقد فائدة الكاش لأنه يُعاد بناؤه باستمرار، ومدة طويلة جداً تُبقي بيانات قديمة تُقدَّم للمستخدم بعد تغيّر مصدرها. القاعدة العملية: اربط مدة الصلاحية بمعدّل تغيّر البيانات، فقائمة تتغيّر كل ساعة تُخزَّن بمدة أقصر من إعدادات لا تتغيّر إلا نادراً. الأخطر من ذلك مشكلة "اندفاع الكاش" (cache stampede): حين تنتهي صلاحية مفتاح شائع فجأة، تندفع مئات الطلبات معاً لإعادة بنائه من قاعدة البيانات في اللحظة نفسها فتشبعها. Redis يعالج هذا بأقفاله وبنى بياناته، إذ يعيد بناء القيمة طلبٌ واحد فقط بينما ينتظر الباقون، وهذه قدرة يصعب تحقيقها ببساطة Memcached. خطأ شائع آخر تخزين بيانات لا تُخزَّن أصلاً: قيمة تخصّ مستخدماً واحداً بمفتاح مشترك، فيرى مستخدم بيانات آخر. اجعل المفتاح دقيقاً يحمل ما يميّز السياق (المستخدم، اللغة، الصفحة)، فالكاش الخاطئ أسوأ من غياب الكاش لأنه يقدّم إجابة خاطئة بثقة.
الخلاصة والقرار
القاعدة المختصرة: إن أردت تخزيناً مؤقتاً بسيطاً لمفتاح وقيمة فقط، وحملاً متوازياً كثيفاً، وقبلت ضياع الكاش عند إعادة التشغيل، فـMemcached كافٍ وأخفّ. أما إن احتجت بنى بيانات أغنى (قوائم، sorted sets، hashes)، أو طوابير وpub/sub، أو ثباتاً بعد إعادة التشغيل، أو سياسات إخلاء دقيقة، فـRedis هو الاختيار، وهو ما يناسب أغلب التطبيقات الحديثة لأنه يجمع دور الكاش والطابور والوسيط في خدمة واحدة. ابدأ بضبط maxmemory وسياسة إخلاء واضحة، وراقب الرام، وتوسّع بترقية فورية حين يكبر كاشك، فتبني على أساس متين لا يتصدّع تحت النمو. النصيحة الأخيرة: لا تختر الأداة بناءً على ضجيج المقارنات، بل على حاجة تطبيقك الفعلية اليوم مع مساحة للنمو غداً. إن بدأت بـMemcached ثم احتجت طوابير أو ثباتاً، فالانتقال لـRedis سهل لأنه يغطّي كل ما كنت تفعله ويزيد، ولهذا يبدأ كثيرون بـRedis مباشرة فلا يعيدون البناء لاحقاً حين تكبر متطلباتهم. أياً كان قرارك، ثبّت الخدمة على سيرفر تملك التحكم فيه بصلاحية الجذر، فتضبط الإعدادات وتراقب الذاكرة وتوسّع بحرية، وهو ما يعطيك خادم سحابي في الرياض بزمن استجابة نحو 8ms قريب من تطبيقك.


