لغة Go بالأمثلة: تحديد المعدل

يُعد تحديد المعدل آلية مهمة للتحكم في استخدام الموارد والحفاظ على جودة الخدمة. تدعم Go تحديد المعدل بأناقة باستخدام روتينات Go والقنوات والمؤقتات الدورية.

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("request", req, time.Now())
    }

قد نرغب في السماح بدفعات قصيرة من الطلبات ضمن آلية تحديد المعدل، مع الحفاظ على المعدل الإجمالي. يمكننا تحقيق ذلك بتخزين قناة تحديد المعدل مؤقتًا. ستسمح القناة burstyLimiter بدفعات تصل إلى 3 أحداث.

    burstyLimiter := make(chan time.Time, 3)

املأ القناة لتمثيل الدفعات المسموح بها.

    for range 3 {
        burstyLimiter <- time.Now()
    }

سنحاول كل 200 مللي ثانية إضافة قيمة جديدة إلى burstyLimiter، حتى حدها البالغ 3 قيم.

    go func() {
        for t := range time.Tick(200 * time.Millisecond) {
            burstyLimiter <- t
        }
    }()

حاكِ الآن 5 طلبات واردة أخرى. ستستفيد الطلبات الثلاثة الأولى من قدرة burstyLimiter على معالجة الدفعات.

    burstyRequests := make(chan int, 5)
    for i := 1; i <= 5; i++ {
        burstyRequests <- i
    }
    close(burstyRequests)
    for req := range burstyRequests {
        <-burstyLimiter
        fmt.Println("request", req, time.Now())
    }
}

عند تشغيل برنامجنا، نرى معالجة الدفعة الأولى من الطلبات بمعدل طلب واحد كل نحو 200 مللي ثانية كما أردنا.

$ go run rate-limiting.go
request 1 2012-10-19 00:38:18.687438 +0000 UTC
request 2 2012-10-19 00:38:18.887471 +0000 UTC
request 3 2012-10-19 00:38:19.087238 +0000 UTC
request 4 2012-10-19 00:38:19.287338 +0000 UTC
request 5 2012-10-19 00:38:19.487331 +0000 UTC

في الدفعة الثانية من الطلبات، نخدم الطلبات الثلاثة الأولى فورًا لأن تحديد المعدل يسمح بالدفعات، ثم نخدم الطلبين المتبقيين بفاصل يبلغ نحو 200 مللي ثانية لكل منهما.

request 1 2012-10-19 00:38:20.487578 +0000 UTC
request 2 2012-10-19 00:38:20.487645 +0000 UTC
request 3 2012-10-19 00:38:20.487676 +0000 UTC
request 4 2012-10-19 00:38:20.687483 +0000 UTC
request 5 2012-10-19 00:38:20.887542 +0000 UTC

المثال التالي: .