تحديد المعدل (Rate limiting) هو آلية مهمة للتحكم في استهلاك الموارد والحفاظ على جودة الخدمة. تدعم Go تحديد المعدل بأناقة باستخدام الـ goroutines والقنوات والمنبهات (tickers).
package main
import (
"fmt"
"time"
)
func main() {
أولاً سننظر في تحديد المعدل الأساسي. لنفترض أننا نريد تحديد معالجتنا للطلبات الواردة. سنقوم بخدمة هذه الطلبات من قناة بنفس الاسم.
requests := make(chan int, 5)
for i := 1; i <= 5; i++ {
requests <- i
}
close(requests)
قناة limiter هذه ستستقبل قيمة كل 200 ملي ثانية. هذا هو المنظم في مخطط تحديد المعدل الخاص بنا.
limiter := time.Tick(200 * time.Millisecond)
من خلال الإعاقة عند الاستقبال من قناة limiter قبل خدمة كل طلب، فإننا نحدد أنفسنا بطلب واحد كل 200 ملي ثانية.
for req := range requests {
<-limiter
fmt.Println("الطلب", req, time.Now())
}
قد نرغب في السماح بدفقات قصيرة (bursts) من الطلبات في مخطط تحديد المعدل مع الحفاظ على حد المعدل العام. يمكننا تحقيق ذلك من خلال تخزين قناة المحدد مؤقتاً. قناة burstyLimiter هذه ستسمح بدفقات تصل إلى 3 أحداث.
burstyLimiter := make(chan time.Time, 3)
املأ القناة لتمثيل الدفقات المسموح بها.
for i := 0; i < 3; i++ {
burstyLimiter <- time.Now()
}
كل 200 ملي ثانية سنحاول إضافة قيمة جديدة إلى burstyLimiter حتى حدها الأقصى وهو 3.
go func() {
for t := range time.Tick(200 * time.Millisecond) {
burstyLimiter <- t
}
}()
الآن لنحاكي 5 طلبات واردة أخرى. أول 3 منها ستستفيد من قدرة الدفق الخاصة بـ burstyLimiter.
burstyRequests := make(chan int, 5)
for i := 1; i <= 5; i++ {
burstyRequests <- i
}
close(burstyRequests)
for req := range burstyRequests {
<-burstyLimiter
fmt.Println("الطلب", req, time.Now())
}
}
عند تشغيل برنامجنا، نرى الدفعة الأولى من الطلبات يتم التعامل معها مرة كل ~200 ملي ثانية كما هو مطلوب. بالنسبة للدفعة الثانية، نقوم بخدمة أول 3 طلبات فوراً بسبب تحديد المعدل القابل للدفق، ثم نخدم الطلبين المتبقيين بتأخير قدره ~200 ملي ثانية لكل منهما.
تشغيل البرنامج:
$ go run rate-limiting.go
الطلب 1 2012-10-19 00:38:18.687438 +0000 UTC
الطلب 2 2012-10-19 00:38:18.887471 +0000 UTC
الطلب 3 2012-10-19 00:38:19.087238 +0000 UTC
الطلب 4 2012-10-19 00:38:19.287338 +0000 UTC
الطلب 5 2012-10-19 00:38:19.487331 +0000 UTC
الطلب 1 2012-10-19 00:38:20.487578 +0000 UTC
الطلب 2 2012-10-19 00:38:20.487645 +0000 UTC
الطلب 3 2012-10-19 00:38:20.487676 +0000 UTC
الطلب 4 2012-10-19 00:38:20.687483 +0000 UTC
الطلب 5 2012-10-19 00:38:20.887542 +0000 UTC المثال التالي: العدادات الذرية (Atomic Counters).