تحديد المعدل (Rate Limiting) في Go (Golang): المكتبات والأنماط وأمثلة التنفيذ

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

تحديد المعدل (Rate Limiting) في Go (Golang): المكتبات والأنماط وأمثلة التنفيذ



تحديد المعدل (Rate Limiting) هو أحد الآليات الأساسية لحماية والتحكم في الحمل في خدمات الويب الحديثة والهندسة المعمارية للخدمات المصغرة. في نظام Go (Golang) البيئي، توجد عدة أدوات ناضجة لتنفيذ تحديد المعدل، بدءًا من الحزمة المدمجة time وصولاً إلى المكتبات المتخصصة مثل golang.org/x/time/rate. في هذه المقالة، سنشرح بالتفصيل كيفية عمل تحديد المعدل في Go، وما هي المكتبات التي يجب استخدامها، وسنقدم أمثلة عملية على الكود.



ما هو تحديد المعدل (Rate Limiting) ولماذا هو مطلوب؟



تحديد المعدل هو تقنية للتحكم في عدد الطلبات التي يمكن للعميل إرسالها إلى الخادم خلال فترة زمنية محددة. الأهداف الرئيسية:

  • الحماية من هجمات DDoS — منع تحميل الخادم الزائد.
  • التوزيع العادل للموارد — تقييد العملاء "الجشعين".
  • الامتثال لاتفاقيات مستوى الخدمة (SLA) — ضمان التوفر لجميع المستخدمين.
  • توفير التكاليف — تقليل الحمل على قواعد البيانات وواجهات API الخارجية.


في Go، يتم تنفيذ تحديد المعدل باستخدام خوارزميات Token Bucket (دلو الرموز) و Leaky Bucket (الدلو المتسرب). الأكثر شيوعًا هو Token Bucket.



مكتبة golang.org/x/time/rate



المكتبة الرئيسية والموصى بها لتحديد المعدل في Go هي golang.org/x/time/rate. وهي تنفذ خوارزمية Token Bucket وتنتمي إلى المجموعة الموسعة لحزم Go (sub-repositories).



التثبيت:

go get golang.org/x/time/rate


المكونات الأساسية

  • rate.Limiter — كائن المحدد الرئيسي.
  • rate.NewLimiter(r rate.Limit, b int) — ينشئ محددًا بمعدل r طلب في الثانية وحجم دلو b.
  • Allow() — يتحقق مما إذا كان يمكن تنفيذ الطلب الآن (غير محظور).
  • Wait(ctx) — يحظر التنفيذ حتى يتوفر رمز مميز (يراعي السياق).
  • Reserve() — يُرجع Reservation، مما يسمح بتأجيل التنفيذ.


مثال 1: محدد معدل أساسي

package main

import ( "fmt" "golang.org/x/time/rate" "time")

func main() { // طلبان في الثانية، دلو بسعة 5 رموز limiter := rate.NewLimiter(2, 5)

for i := 0; i < 10; i++ { if limiter.Allow() { fmt.Printf("تم تنفيذ الطلب %d", i) } else { fmt.Printf("تم رفض الطلب %d (حد)", i) } time.Sleep(200 * time.Millisecond) }}


مثال 2: محدد معدل مع الانتظار (Wait)

package main

import ( "context" "fmt" "golang.org/x/time/rate" "time")

func main() { limiter := rate.NewLimiter(1, 3) // طلب واحد في الثانية، دلو بسعة 3 ctx := context.Background()

for i := 0; i < 6; i++ { err := limiter.Wait(ctx) if err != nil { fmt.Println("خطأ في الانتظار:", err) return } fmt.Printf("تم تنفيذ الطلب %d في %s", i, time.Now().Format("15:04:05.000")) }}


تنفيذ HTTP middleware مع تحديد المعدل



عمليًا، يتم تطبيق تحديد المعدل في أغلب الأحيان على مستوى خادم HTTP. لنلقِ نظرة على مثال middleware لـ Gin أو net/http القياسي.



package main

import ( "net/http" "golang.org/x/time/rate")

// RateLimiterMiddleware يُرجع middleware مع تحديد معدلfunc RateLimiterMiddleware(r rate.Limit, b int) func(http.Handler) http.Handler { limiter := rate.NewLimiter(r, b) return func(next http.Handler) http.Handler { return http.HandlerFunc(f

توصيات