التخزين المؤقت الموزع باستخدام Redis و Memcached
التخزين المؤقت الموزع باستخدام Redis و Memcached
التخزين المؤقت على خادم واحد لا يفيد إلا ذلك الخادم بعينه. حين تتوسّع أفقياً بإضافة خادم تطبيقات ثانٍ وثالث، يمتلك كل خادم ذاكرته المؤقتة المحلية المستقلة، وسرعان ما تتضارب هذه الذاكرات. خادم يُعيد سعراً قديماً، وآخر يُعيد السعر المحدَّث. المستخدمون الذين يصلون عبر نسخ مختلفة يرون بيانات مختلفة. هذه تحديداً هي المشكلة التي يحلّها التخزين المؤقت الموزع: مخزن بيانات مشترك في الذاكرة تقرأ منه وتكتب إليه جميع عُقد التطبيق، مما يمنح الأسطول بأكمله رؤية موحَّدة ومتسقة للحالة المخزَّنة مؤقتاً.
لماذا نضع الذاكرة المؤقتة في الـ RAM؟
الذاكرة العشوائية أسرع من القرص بمراتب. عملية GET في Redis تنتهي عادةً في أقل من 1 ميلي ثانية على شبكة مركز البيانات ذاته، بينما قد تستغرق استعلامات PostgreSQL التي تصل إلى القرص ما بين 50 و200 ميلي ثانية. لصفحة تجمع بيانات من اثني عشر استعلاماً، يعني تخزين نتائج هذه الاستعلامات مؤقتاً تقديم الصفحة كاملة في أجزاء من المللي ثانية بدلاً من نصف ثانية. عند معدل 10,000 طلب في الثانية، هذا الفارق يحدد الفرق بين أسطول من 5 خوادم وأسطول من 50.
Redis مقابل Memcached — اختيار الأداة المناسبة
كلاهما مُختبَر في المعارك الكبرى، سريع للغاية، ومدعوم على نطاق واسع. الفارق يكمن في النطاق:
- Memcached مبسَّط عمداً: مفتاح نصي إلى قيمة نصية، متعدد الخيوط، بلا استمرارية، بلا نسخ متماثل مدمج. يفعل شيئاً واحداً ويفعله بسرعة. إذا كل ما تحتاجه هو ذاكرة مؤقتة بسيطة للكائنات وتريد أبسط نمط تشغيلي ممكن، فـ Memcached خيار متين. فيسبوك لا يزال يشغّله بحجم هائل لهذا السبب تحديداً.
- Redis يدعم هياكل بيانات غنية — سلاسل نصية، جداول هاش، قوائم، مجموعات مرتبة، مجموعات، تدفقات، خرائط بتات، HyperLogLogs — إضافة إلى الاستمرارية، النشر/الاشتراك، الكتابة بلغة Lua، وضع الكتلة، وتوافر عالٍ قائم على Sentinel. في الممارسة، أصبح Redis الخيار الافتراضي للأنظمة الجديدة لأنه يمكن أن يحل محل عدة أدوات منفصلة في آنٍ واحد (ذاكرة مؤقتة، قائمة انتظار رسائل، لوحة متصدرين، مخزن جلسات، عداد تقييد معدل).
هياكل بيانات Redis التي تغيّر تصميم الأنظمة
سبب تفوّق Redis على أدوات التخزين المؤقت البسيطة هو أن أنواعه الأصيلة تتطابق مباشرة مع أنماط تصميم الأنظمة الشائعة:
- Hash — تخزين ملف تعريف المستخدم بالكامل:
HSET user:42 name "Alice" role "admin" plan "pro". تحديث الحقول الفردية بشكل ذري دون جلب الكائن بأكمله وإعادة تسلسله. - Sorted Set (ZSET) — لوحات المتصدرين:
ZADD game:scores 9820 "alice". ترجعZRANGE … WITHSCORESأفضل N في O(log N). - List — قوائم انتظار الوظائف وتغذيات الأنشطة.
LPUSH/BRPOPينفّذ قائمة انتظار حجب دون استطلاع. - Set — الزوار الفريدون يومياً، تقاطعات المجموعات ("المستخدمون الذين اشتروا A وB معاً").
- عدّادات ذرية —
INCR rate:ip:1.2.3.4معEXPIREهو تقييد المعدل الكلاسيكي: لا معاملات، لا أقفال، دورة واحدة.
Redis Cluster والتجزئة
عُقدة Redis واحدة تبلغ سعتها القصوى ما تتيحه ذاكرة RAM للمضيف — عادةً 32 إلى 128 جيجابايت في الإنتاج. وراء ذلك، تحتاج إلى التجزئة. يستخدم Redis Cluster التجزئة المتسقة على 16,384 فتحة: كل مفتاح يُربط بفتحة عبر CRC16(key) mod 16384، والفتحات مقسّمة بين العُقد الرئيسية. كل رئيسية لها نسخة متماثلة واحدة أو أكثر للتعافي من الأعطال. يتلقى العملاء إعادة توجيه MOVED أو ASK حين يصلون إلى العُقدة الخاطئة، والعملاء المدركون للكتلة يخزّنون خريطة الفتحات مؤقتاً لتجنب رحلات إضافية.
الأنماط التشغيلية
تجميع الاتصالات: فتح اتصال TCP إلى Redis مع كل طلب مكلف. يجب على كل خادم تطبيق الاحتفاظ بمجموعة ثابتة من الاتصالات (عادةً 10 إلى 50) وإعادة استخدامها. معظم مكتبات عملاء Redis تفعل هذا تلقائياً.
التأنيب (Pipelining): إرسال أوامر متعددة في رحلة شبكية واحدة يُقلّل زمن الاستجابة لكل أمر بشكل كبير حين تحتاج إلى جلب أو تعيين عشرات المفاتيح دفعة واحدة. معظم العملاء يتيحون واجهة pipeline() أو multi().
تصميم المفاتيح: استخدم مفاتيح منظمة ومقسَّمة بالنطاق — product:1234:detail، user:42:session — للحفاظ على فضاء المفاتيح مقروءاً وتمكين العمليات القائمة على الأنماط مثل SCAN. تجنّب KEYS * في الإنتاج؛ إنها تحجب حلقة الأحداث على فضاءات المفاتيح الكبيرة.
KEYS * على ملايين المفاتيح سيحجب كل أمر آخر لثوانٍ، مما يجعل الذاكرة المؤقتة غير متاحة فعلياً. استخدم SCAN مع مؤشر ومؤشر COUNT صغير بدلاً منه — فهو يتكرر بشكل تدريجي دون حجب.
التوافر العالي: Sentinel مقابل Cluster
للنشر الأصغر الذي لا يحتاج إلى تجزئة، يوفّر Redis Sentinel توافراً عالياً دون تعقيد وضع الكتلة: رئيسية واحدة، نسخة متماثلة أو أكثر، وثلاثة عمليات Sentinel أو أكثر تتصوّت لترقية نسخة متماثلة حين تصبح الرئيسية غير متاحة. يتصل العملاء بـ Sentinel أولاً لاكتشاف عنوان الرئيسية الحالي. وضع الكتلة يتعامل مع التجزئة والتعافي من الأعطال معاً في نظام واحد، مما يجعله الخيار الأفضل حين تتجاوز مجموعة بياناتك سعة عُقدة واحدة.
كلٌّ من Redis وMemcached ناضج ومُختبَر في الإنتاج وقادر على التعامل مع الملايين من العمليات في الثانية على أجهزة عادية. القرار بينهما — وبين معماريات مثل Sentinel أو Cluster أو الخدمات المُدارة كـ Amazon ElastiCache أو Google Memorystore — يتوقف على أي مجموعة من البساطة والميزات والتكلفة التشغيلية تناسب فريقك وحجم عملك.