تحديد معدل الطلبات في Go: دليل شامل للحد من سرعة الطلبات
\n\nتحديد معدل الطلبات (Rate Limiting) هو آلية أساسية للحماية وإدارة الحمل في تطبيقات الويب الحديثة والخدمات المصغرة. في لغة Go (Golang)، توجد العديد من الأساليب والمكتبات لتطبيق تحديد معدل الطلبات، من البسيطة إلى المتقدمة. في هذه المقالة، سنشرح المفاهيم الأساسية والمكتبات الشائعة ونعرض أمثلة على الكود.
\n\nما هو تحديد معدل الطلبات ولماذا هو مطلوب؟
\n\nتحديد معدل الطلبات هو تقنية للتحكم في عدد الطلبات التي يمكن للعميل إرسالها خلال فترة زمنية محددة. الأهداف الرئيسية:
\n\n- \n
- الحماية من هجمات DDoS — منع تحميل الخادم الزائد \n
- التوزيع العادل للموارد — وصول متساوٍ لجميع المستخدمين \n
- توفير الموارد — تقليل تكاليف البنية التحتية \n
- منع إساءة الاستخدام — الحماية من السكرابينغ والهجمات القسرية \n
الخوارزميات الأساسية لتحديد معدل الطلبات
\n\nتوجد عدة خوارزميات كلاسيكية، لكل منها مزاياها:
\n\n- \n
- Token Bucket (دلو الرموز) — الخوارزمية الأكثر شيوعًا، حيث تتراكم "الرموز" بمعدل معين \n
- Leaky Bucket (الدلو المتسرب) — تتم معالجة الطلبات بمعدل ثابت، ويتم تجاهل الفائض \n
- Fixed Window (النافذة الثابتة) — عداد بسيط للطلبات خلال فترة زمنية ثابتة \n
- Sliding Window (النافذة المنزلقة) — أكثر دقة من النافذة الثابتة، مع مراعاة الحدود الزمنية \n
المكتبات الشائعة لتحديد معدل الطلبات في Go
\n\n1. المكتبة القياسية: golang.org/x/time/rate
\n\nهذا امتداد رسمي من فريق Go، يطبق خوارزمية Token Bucket. إنها خفيفة الوزن وسهلة الاستخدام ومناسبة تمامًا لمعظم السيناريوهات.
\n\npackage main\n\nimport (\n "fmt"\n "net/http"\n "time"\n "golang.org/x/time/rate"\n)\n\nfunc main() {\n // إنشاء محدد: طلبان في الثانية، مع burst 5\n limiter := rate.NewLimiter(2, 5)\n\n http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {\n if !limiter.Allow() {\n http.Error(w, "طلبات كثيرة جدًا", http.StatusTooManyRequests)\n return\n }\n fmt.Fprintf(w, "OK: %s", time.Now().Format(time.RFC3339))\n })\n\n http.ListenAndServe(":8080", nil)\n}\n\n2. github.com/ulule/limiter
\n\nمكتبة أكثر مرونة مع دعم مخازن مختلفة (Redis، Memcached، in-memory) وخوارزميات. مناسبة للأنظمة الموزعة.
\n\nimport (\n "github.com/gin-gonic/gin"\n "github.com/ulule/limiter/v3"\n "github.com/ulule/limiter/v3/drivers/store/memory"\n)\n\nfunc main() {\n // الإعداد: 10 طلبات في الثانية\n rate := limiter.Rate{\n Period: 1 * time.Second,\n Limit: 10,\n }\n\n store := memory.NewStore()\n instance := limiter.New(store, rate)\n\n r := gin.Default()\n r.Use(func(c *gin.Context) {\n key := c.ClientIP()\n context, err := instance.Get(c.Request.Context(), key)\n if err != nil {\n c.AbortWithStatusJSON(500, gin.H{"error": "خطأ داخلي"})\n return\n }\n if context.Reached {\n c.AbortWithStatusJSON(429, gin.H{"error": "طلبات كثيرة جدًا"})\n return\n }\n c.Next()\n })\n\n r.Run(":8080")\n}\n\n3. github.com/juju/ratelimit
\n\nمكتبة بسيطة وموثوقة من Canonical، تعتمد على خوارزمية Token Bucket. تتميز بواجهة برمجة تطبيقات بسيطة.
\n\nimport (\n "github.com/juju/ratelimit"\n "time"\n)\n\nfunc main() {\n // إنشاء bucket: 100 رمز، إعادة تعبئة 10 رموز في الثانية\n bucket :=