التخزين المؤقت في Go (Golang): Redis وأدوات أخرى
التخزين المؤقت هو أحد الآليات الرئيسية لتحسين أداء تطبيقات الويب والخدمات المصغرة. في نظام Go (Golang) البيئي، توجد العديد من المكتبات لتنفيذ التخزين المؤقت، بدءًا من الحلول البسيطة في الذاكرة وصولاً إلى الأنظمة الموزعة القائمة على Redis. في هذه المقالة، سنقوم بتحليل ثلاثة مناهج رئيسية بالتفصيل: هياكل البيانات المضمنة (sync.Map)، والمكتبات الشائعة للتخزين المؤقت في الذاكرة (go-cache، freecache، bigcache)، والتكامل مع Redis.
1. الأدوات المضمنة: sync.Map
توفر Go خريطة آمنة للخيوط — sync.Map. وهي مناسبة للتخزين المؤقت البسيط بكمية صغيرة من البيانات وتحديثات نادرة. ومع ذلك، فإن أداءها تحت الأحمال العالية يكون أقل من المكتبات المتخصصة.
مثال على استخدام sync.Map:
package main
import ( "fmt" "sync" "time")
func main() { var cache sync.Map
// كتابة cache.Store("user:42", map[string]interface{}{ "name": "Alice", "age": 30, })
// قراءة مع التحقق if val, ok := cache.Load("user:42"); ok { fmt.Println("تم العثور على التخزين المؤقت:", val) }
// حذف cache.Delete("user:42")
// تخزين مؤقت مع TTL (يجب تنفيذه يدويًا) cache.Store("session:abc", time.Now().Unix())}العيوب: عدم وجود TTL تلقائي، مجموعة محدودة من العمليات، مشاكل محتملة في الأداء مع عمليات الكتابة المتكررة.
2. مكتبات التخزين المؤقت في الذاكرة
للسيناريوهات الأكثر تعقيدًا، استخدم المكتبات المتخصصة. دعنا ننظر في ثلاثة مكتبات شائعة:
2.1 go-cache
مكتبة بسيطة مع دعم TTL. مثالية للمشاريع الصغيرة.
import "github.com/patrickmn/go-cache"
func main() { c := cache.New(5*time.Minute, 10*time.Minute) // TTL افتراضي، فاصل التنظيف
c.Set("key", "value", cache.DefaultExpiration) val, found := c.Get("key") if found { fmt.Println(val) }}2.2 freecache
مكتبة بحجم ذاكرة ثابت (بدون حمل GC). تدعم TTL وأداء عالي.
import "github.com/coocood/freecache"
func main() { cache := freecache.NewCache(100 * 1024 * 1024) // 100 MB
cache.Set([]byte("mykey"), []byte("myvalue"), 60) // TTL 60 ثانية val, err := cache.Get([]byte("mykey")) if err == nil { fmt.Println(string(val)) }}2.3 bigcache
محسّنة لتخزين كميات كبيرة من البيانات دون توقف GC. تعمل مع البيانات المسلسلة.
import "github.com/allegro/bigcache/v3"
func main() { cache, _ := bigcache.NewBigCache(bigcache.DefaultConfig(10 * time.Minute))
cache.Set("key", []byte("value")) val, _ := cache.Get("key") fmt.Println(string(val))}3. Redis: التخزين المؤقت الموزع
بالنسبة للأنظمة الموزعة والخدمات المصغرة، يظل Redis هو المعيار الفعلي. في Go، استخدم مكتبة go-redis/redis (v9+).
الاتصال والعمليات الأساسية:
import ( "context" "fmt" "github.com/redis/go-redis/v9")
func main() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", DB: 0, })
// تعيين قيمة مع TTL err := rdb.Set(ctx, "user:42", `{"name":"Bob"}`, 10*time.Minute).Err() if err != nil { panic(err) }
// قراءة val, err := rdb.Get(ctx, "user:42").Result() if err == redis.Nil { fmt.Println("لم يتم العثور على التخزين المؤقت") } else if err != nil { panic(err) } else { fmt.Println("القيمة:", val) }}الإمكانيات المتقدمة لـ Redis في Go:
- Pipeline