مقدمة: لماذا التخزين المؤقت ضروري لأداء C++
\nفي التطوير الحديث عالي التحميل بلغة C++، لم يعد التخزين المؤقت خيارًا - بل أصبح عنصرًا إلزاميًا في البنية. بدونه، أي نظام CRUD أو خدمة مصغرة ستواجه بسرعة حدود قاعدة البيانات، وستنمو زمن الاستجابة للطلبات بشكل أسي. على المستوى المتقدم، نواجه معضلة: استخدام أنظمة خارجية (Redis، Memcached) أو نشر حل تخزين مؤقت خاص في الذاكرة بلغة C++؟ في هذه المقالة، سنحلل الإيجابيات والسلبيات والتنفيذات المحددة لكل نهج، بناءً على ممارسة العمل مع قوائم انتظار الشبكة، والأقفال، والتسلسل.
\n\n1. Redis: المرونة وهياكل البيانات
\nRedis ليس مجرد مخزن key-value. ميزته الرئيسية هي مجموعة غنية من أنواع البيانات: السلاسل، التجزئات، القوائم، المجموعات، المجموعات المرتبة. بالنسبة لـ C++، هناك عدة عملاء: redis-plus-plus (موصى به) و hiredis (مستوى منخفض).
مثال على الاتصال والعمليات الأساسية مع redis-plus-plus
\n#include <sw/redis++/redis++.h>\n#include <iostream>\n\nint main() {\n // الاتصال بـ Redis (افتراضيًا localhost:6379)\n sw::redis::Redis redis("tcp://127.0.0.1:6379");\n\n // تعيين قيمة مع TTL لمدة 60 ثانية\n redis.set("user:1001", "John Doe", std::chrono::seconds(60));\n\n // القراءة\n auto val = redis.get("user:1001");\n if (val) {\n std::cout << "User: " << *val << std::endl;\n }\n\n // العمل مع التجزئات\n redis.hset("session:abc", "token", "xyz123");\n redis.hset("session:abc", "expires", "3600");\n auto token = redis.hget("session:abc", "token");\n std::cout << "Token: " << *token << std::endl;\n\n return 0;\n}\n\nميزات متقدمة: استخدام المعاملات عبر redis.multi() و redis.exec()، بالإضافة إلى Pub/Sub للإشعارات بإبطال التخزين المؤقت. Redis مناسب تمامًا عندما تحتاج إلى تخزين هياكل معقدة مع عمليات ذرية (مثل زيادة العداد).
2. Memcached: السرعة والبساطة
\nMemcached هو كاش موزع خفيف الوزن، محسّن لتخزين البيانات المسطحة (السلاسل والكتل الثنائية). لا يدعم المعاملات أو الهياكل المعقدة، لكنه يتفوق في السرعة والاستهلاك الأدنى للذاكرة. بالنسبة لـ C++، نستخدم مكتبة libmemcached.
مثال على العمل مع Memcached عبر libmemcached
\n#include <libmemcached/memcached.h>\n#include <iostream>\n#include <cstring>\n\nint main() {\n memcached_st *memc = memcached_create(nullptr);\n memcached_server_st *servers = nullptr;\n memcached_return_t rc;\n\n // إضافة خادم\n servers = memcached_server_list_append(servers, "127.0.0.1", 11211, &rc);\n rc = memcached_server_push(memc, servers);\n if (rc != MEMCACHED_SUCCESS) {\n std::cerr << "Error: " << memcached_strerror(memc, rc) << std::endl;\n return 1;\n }\n\n // كتابة مع TTL لمدة 30 ثانية\n const char *key = "config:db_host";\n const char *value = "10.0.0.1";\n rc = memcached_set(memc, key, strlen(key), value, strlen(value), \n std::time(0) + 30, (uint32_t)0);\n if (rc != MEMCACHED_SUCCESS) {\n std::cerr << "Set failed: " << memcached_strerror(memc, rc) << std::endl;\n }\n\n // القراءة\n size_t val_len;\n uint32_t flags;\n char *retrieved = memcached_get(memc, key, strlen(key), &val_len, &flags, &rc);\n if (rc == MEMCACHED_SUCCESS) {\n std::cout << "DB Host: " << retrieved << std::endl;\n free(retrieved);\n }\n\n memcached_free(memc);\n return 0;\n}\n\nمتى تختار Memcached؟ إذا كنت بحاجة إلى كاش بسيط للكائنات المسلسلة، دون الحاجة إلى تخزين هياكل معقدة. Memcached مثالي لتخزين نتائج استعلامات SQL أو أجزاء HTML مؤقتًا.