مقدمة: لماذا نحتاج التخزين المؤقت في C++؟
في البرمجيات الحديثة عالية التحميل، سرعة الوصول إلى البيانات أمر بالغ الأهمية. سواء كان خادم ويب يعالج ملايين الطلبات، أو محطة تداول عالية التردد - فإن كل استعلام إضافي لقاعدة البيانات أو قرص بطيء يمكن أن يصبح عنق زجاجة. هنا يأتي دور التخزين المؤقت - تقنية تخزين البيانات المطلوبة بشكل متكرر في ذاكرة سريعة (RAM) للوصول الفوري لاحقًا.
توفر لغة C++ للمطور إمكانيات فريدة لبناء أنظمة تخزين مؤقت فعالة: من التحكم الدقيق في الذاكرة إلى استخدام أدوات خارجية قوية. في هذه المقالة، سننتقل من الحلول المدمجة البسيطة إلى الأنظمة الصناعية مثل Redis وMemcached، وسنناقش متى وأي نهج نختار.
ستتعلم:
- كيفية تنفيذ ذاكرة تخزين مؤقت بسيطة في C++ بدون مكتبات خارجية.
- كيفية ربط واستخدام Redis وMemcached.
- مقارنة الأداء وسيناريوهات الاستخدام لكل نهج.
الحلول المدمجة: ذاكرة التخزين المؤقت الخاصة بك في C++
قبل ربط الخدمات الخارجية، من الجدير فهم أنه بالنسبة للعديد من المهام، تكون ذاكرة التخزين المؤقت المدمجة كافية. المزايا الرئيسية: زمن انتقال شبكة صفري، سهولة النشر، والتحكم الكامل في البيانات.
أبسط ذاكرة تخزين مؤقت باستخدام std::unordered_map
الخيار الأساسي هو استخدام مصفوفة ترابطية. ومع ذلك، ليس لديها آلية لإزالة البيانات (eviction policy) وستنمو إلى أجل غير مسمى، مما قد يؤدي إلى تجاوز الذاكرة.
#include <unordered_map>#include <string>
class SimpleCache { std::unordered_map<std::string, std::string> cache_;public: void put(const std::string& key, const std::string& value) { cache_[key] = value; } std::string get(const std::string& key) { auto it = cache_.find(key); if (it != cache_.end()) { return it->second; } return ""; // أو إلقاء استثناء }};ذاكرة التخزين المؤقت LRU (الأقل استخدامًا مؤخرًا)
حل أكثر تقدمًا هو ذاكرة التخزين المؤقت LRU، التي تزيل العناصر الأقل استخدامًا عند الوصول إلى الحد الأقصى. يتطلب التنفيذ مزيجًا من جدول التجزئة وقائمة مرتبطة مزدوجة.
#include <list>#include <unordered_map>
template<typename K, typename V>class LRUCache { size_t capacity_; std::list<std::pair<K, V>> items_; std::unordered_map<K, typename std::list<std::pair<K, V>>::iterator> cache_;
public: LRUCache(size_t cap) : capacity_(cap) {}
V get(const K& key) { auto it = cache_.find(key); if (it == cache_.end()) { throw std::runtime_error("Key not found"); } items_.splice(items_.begin(), items_, it->second); return it->second->second; }
void put(const K& key, const V& value) { auto it = cache_.find(key); if (it != cache_.end()) { it->second->second = value; items_.splice(items_.begin(), items_, it->second); return; } if (items_.size() == capacity_) { auto last = items_.back(); cache_.erase(last.first); items_.pop_back(); } items_.emplace_front(key, value); cache_[key] = items_.begin(); }};مثل هذه الذاكرة المؤقتة مثالية للعمل في عملية واحدة، عندما تنتمي البيانات إلى هذه العملية فقط ولا تتطلب مزامنة.
Memcached: ذاكرة تخزين مؤقت موزعة للبيانات البسيطة
Memcached هو نظام تخزين مؤقت خفيف الوزن وعالي الأداء يعمل عبر بروتوكول TCP/UDP. يخزن البيانات في ذاكرة الوصول العشوائي ولا يدعم الثبات (persistence). خيار ممتاز لتخزين البيانات مؤقتًا