مقدمة: لماذا نحتاج إلى التخزين المؤقت في Go على المستوى المتقدم؟
\n\nفي الأنظمة عالية التحميل بلغة Go (Golang)، غالبًا ما تصبح سرعة الوصول إلى البيانات عنق الزجاجة. قاعدة البيانات ليست دائمًا قادرة على معالجة آلاف الطلبات في الثانية دون تأخيرات كبيرة. التخزين المؤقت هو أداة رئيسية لتقليل الحمل على قاعدة البيانات وتسريع استجابة API.
\n\nعلى المستوى المبتدئ، غالبًا ما يستخدم المطورون map بسيطة مع أقفال (mutexes). ومع ذلك، في بيئة الإنتاج، هناك حاجة إلى حلول أكثر تقدمًا: التخزين المؤقت الموزع (Redis، Memcached) ومكتبات in-memory عالية الأداء (BigCache، FreeCache). في هذه المقالة، سنشرح ميزاتها، ونقارن أداءها، ونعرض أمثلة على الكود بلغة Go لكل خيار.
1. الحلول المدمجة: sync.Map ومكتبات BigCache/FreeCache
\n\n1.1. sync.Map - عندما لا تحتاج إلى تبعية خارجية
\n\nحزمة sync.Map هي map آمنة للخيوط، محسنة للسيناريوهات التي يتم فيها كتابة المفاتيح مرة واحدة وقراءتها عدة مرات. لا تتطلب أقفالًا للقراءة، مما يعطي زيادة في الأداء.
مثال على الاستخدام:
\npackage main\n\nimport (\n "fmt"\n "sync"\n)\n\nfunc main() {\n var cache sync.Map\n\n // كتابة\n cache.Store("user:1", "Alice")\n\n // قراءة\n if value, ok := cache.Load("user:1"); ok {\n fmt.Println("تم العثور على:", value)\n }\n\n // حذف\n cache.Delete("user:1")\n}\n\nالعيوب: لا يوجد إبطال تلقائي بناءً على TTL، ولا يوجد حد للذاكرة. مناسب للتخزين المؤقت المؤقت للتكوينات أو البيانات نادرة التغيير.
\n\n1.2. BigCache - تخزين مؤقت سريع in-memory مع TTL
\n\nBigCache من Allegro هي مكتبة تخزن البيانات في مصفوفات بايت، متجنبة النفقات العامة لـ GC. تدعم TTL والإخلاء التلقائي للسجلات القديمة.
\n\nمثال:
\nimport (\n "github.com/allegro/bigcache/v3"\n "time"\n)\n\nfunc main() {\n cache, _ := bigcache.NewBigCache(bigcache.DefaultConfig(10 * time.Minute))\n\n // كتابة\n cache.Set("mykey", []byte("myvalue"))\n\n // قراءة\n entry, _ := cache.Get("mykey")\n println(string(entry))\n}\n\nالمزايا: ضغط ضئيل على GC، سرعة عالية (ملايين العمليات في الثانية). العيوب: يتم تخزين البيانات فقط بالبايت، لا يوجد دعم للهياكل المعقدة بدون تسلسل.
\n\n1.3. FreeCache - بديل بحجم ثابت
\n\nFreeCache هي مكتبة in-memory أخرى بحجم تخزين مؤقت قابل للتخصيص. تستخدم التقسيم (segmentation) لتقليل الأقفال.
\n\nimport "github.com/coocood/freecache"\n\nfunc main() {\n // حجم التخزين المؤقت - 100 ميجابايت\n cache := freecache.NewCache(100 * 1024 * 1024)\n\n cache.Set([]byte("key"), []byte("value"), 60) // TTL 60 ثانية\n got, _ := cache.Get([]byte("key"))\n println(string(got))\n}\n\n2. Redis - التخزين المؤقت الموزع مع هياكل متقدمة
\n\nRedis هو التخزين المؤقت الخارجي الأكثر شيوعًا لتطبيقات Go. لا يدعم السلاسل النصية فحسب، بل يدعم أيضًا القوائم والتجزئات والمجموعات، بالإضافة إلى TTL وPub/Sub والمعاملات.
\n\n2.1. الاتصال والعمليات الأساسية
\n\nللعمل مع Redis في Go، يتم استخدام برنامج التشغيل go-redis/redis (أو redis/v8).
import (\n "github.com/go-redis/redis/v8"\n "context"\n)\n\nvar ctx = context.Background()\n\nfunc main() {\n rdb := redis.NewClient(&redis.Options{\n Addr: "localhost:6379",\n Password: "",\n DB: 0,\n })\n\n // تعيين مع TTL لمدة 10 ثوانٍ\n err := rdb.Set(ctx, "key", "value", 10*time.Second).Err()\n if err != nil {\n panic(err)\n }\n\n val, err := rdb.Get(c