التخزين المؤقت في Go: Redis وMemcached والحلول المدمجة
التخزين المؤقت هو أحد الأدوات الرئيسية لتحسين أداء تطبيقات الويب والخدمات. في نظام Go (Golang)، يتوفر للمطورين أنظمة تخزين مؤقت خارجية (Redis، Memcached) بالإضافة إلى حلول مدمجة مثل sync.Map أو مكتبات bigcache وfreecache. في هذه المقالة، سنستعرض إيجابيات وسلبيات كل نهج، ونقدم أمثلة على الكود، ونساعدك في اختيار الأداة المثلى لمشروعك.
1. التخزين المؤقت المدمج: sync.Map وmap مع كائن المزامنة (mutex)
توفر Go أدوات أولية لإنشاء ذاكرة تخزين مؤقت مباشرة في ذاكرة التطبيق. الطريقة الأبسط هي استخدام map عادي مع كائن مزامنة (mutex) لضمان أمان الخيوط.
مثال: ذاكرة تخزين مؤقت بسيطة وآمنة للخيوط
package main
import ( "fmt" "sync" "time")
type Cache struct { mu sync.RWMutex items map[string]interface{}}
func NewCache() *Cache { return &Cache{ items: make(map[string]interface{}), }}
func (c *Cache) Set(key string, value interface{}) { c.mu.Lock() defer c.mu.Unlock() c.items[key] = value}
func (c *Cache) Get(key string) (interface{}, bool) { c.mu.RLock() defer c.mu.RUnlock() val, ok := c.items[key] return val, ok}
func main() { cache := NewCache() cache.Set("user:1", "Alice") val, _ := cache.Get("user:1") fmt.Println(val) // Alice}للسيناريوهات الأكثر تعقيدًا، توفر Go sync.Map وهي خريطة تنافسية محسّنة، مناسبة بشكل أفضل للحالات التي يتم فيها كتابة المفاتيح مرة واحدة وقراءتها عدة مرات.
متى نستخدم التخزين المؤقت المدمج؟
- التخزين المؤقت الصغير (micro-caching) (لمدة طلب واحد أو جلسة واحدة).
- تطبيقات singleton بدون بنية موزعة.
- البساطة — لا حاجة لتشغيل خدمات خارجية.
السلبيات: عدم وجود إبطال تلقائي، حجم محدود (يعتمد على ذاكرة التطبيق)، وعدم وجود استمرارية (persistence).
2. BigCache وFreeCache: حلول خفيفة الوزن داخل الذاكرة (in-memory)
مكتبات bigcache وfreecache تحل مشكلة الذاكرة المحدودة وGC (جمع القمامة). تستخدم هذه المكتبات مخازن مؤقتة مخصصة مسبقًا وتقلل الحمل على جامع القمامة في Go.
مثال مع BigCache
package main
import ( "fmt" "github.com/allegro/bigcache/v3" "time")
func main() { cache, _ := bigcache.NewBigCache(bigcache.DefaultConfig(10 * time.Minute)) cache.Set("mykey", []byte("myvalue")) val, _ := cache.Get("mykey") fmt.Println(string(val)) // myvalue}مثال مع FreeCache
package main
import ( "fmt" "github.com/coocood/freecache")
func main() { cache := freecache.NewCache(100 * 1024) // 100 KB cache.Set([]byte("key"), []byte("value"), 60) // TTL 60 ثانية val, _ := cache.Get([]byte("key")) fmt.Println(string(val)) // value}كلتا المكتبتين تدعمان TTL (وقت الحياة) والحذف التلقائي للسجلات القديمة. BigCache أفضل للكميات الكبيرة من البيانات (مئات الجيجابايت)، بينما FreeCache أفضل للسيناريوهات ذات عمليات الكتابة/القراءة المتكررة.
3. Redis: التخزين المؤقت الموزع للإنتاج (Production)
Redis هو الخيار الأكثر شيوعًا للتخزين المؤقت في مشاريع Go. يعمل كخادم منفصل، ويدعم هياكل بيانات معقدة، والاستمرارية (persistence)، والتجميع (clustering).
توصيل Redis في Go
package main
import ( "context" "fmt" "github.com/redis/go-redis/v9")
func main() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", DB:
```