"إذا أراد العامل أن يؤدي عمله بشكل جيد، فعليه أولاً أن يشحذ أدواته." - كونفوشيوس، "مختارات كونفوشيوس. لو لينجونج"
الصفحة الأمامية > برمجة > التحكم في حد معدل الصادر

التحكم في حد معدل الصادر

تم النشر بتاريخ 2024-07-30
تصفح:519

لنتخيل سيناريو مفاده أن أحد الأشخاص لديه تطبيق موزع يتفاعل مع واجهة برمجة تطبيقات تابعة لجهة خارجية. عادةً ما تتمتع واجهات برمجة التطبيقات التابعة لجهات خارجية بآلية تحكم في الحد الأقصى للمعدل لتجنب عملائها من الطلبات المتفجرة والتسبب في تعطل خدماتهم. في مثل هذا السيناريو، كيف يمكن للمتصل التحكم في معدل الطلبات الصادرة إلى واجهة برمجة تطبيقات الطرف الثالث في بيئة موزعة؟ يناقش هذا المنشور استراتيجية محتملة لهذه المشكلة.

توجد خوارزميات متعددة للتحكم في معدل الطلبات، لكننا سنركز هنا على خوارزمية مجموعة الرمز المميز، لأنها سهلة الفهم والتنفيذ نسبيًا. تنص هذه الخوارزمية على ما يلي: يمكن للحاوية أن تحتوي على الحد الأقصى من الرموز المميزة T، وعندما يريد تطبيق ما تقديم طلب إلى واجهة برمجة تطبيقات الطرف الثالث، يجب أن يستغرق 1 رمز من الدلو. إذا كانت المجموعة فارغة، فيجب الانتظار حتى يكون هناك رمز مميز 1 على الأقل في المجموعة. أيضًا، تتم إعادة ملء المجموعة برمز 1 بمعدل ثابت قدره R رمز مميز/ملي ثانية.

من السهل جدًا فهم خوارزمية مجموعة الرمز المميز، ولكن كيف يمكن لأي شخص استخدامها في بيئة موزعة للتحكم في الطلب الصادر إلى واجهات برمجة تطبيقات الطرف الثالث؟

إذا أراد المرء التحكم في حد المعدل الصادر في بيئة موزعة، فمن الضروري وجود مصدر مركزي للحقيقة بالنسبة لحد المعدل الحالي. هناك طرق متعددة لتنفيذ مصدر الحقيقة ولقد قمت بإضفاء الطابع المثالي على الرسم البياني التالي مع إمكانية التنفيذ:

Controlling outgoing rate limit

في الشكل أعلاه، لدينا تطبيق موزع في عدة حجرات، ويمكن لكل حجرة تقديم طلبات إلى واجهة برمجة تطبيقات تابعة لجهة خارجية. يوجد في البنية التحتية للتطبيقات خادم TCP الذي يتحكم في حد المعدل باستخدام خوارزمية مجموعة الرمز المميز. قبل تقديم طلب إلى واجهة برمجة تطبيقات الطرف الثالث، تطلب الكبسولة من خادم TCP رمزًا مميزًا جديدًا، وتنتظر الكبسولة استجابة من خادم TCP حتى يتوفر رمز مميز واحد على الأقل. بعد توفر الرمز المميز، تقدم الكبسولة الطلب إلى واجهة برمجة تطبيقات الطرف الثالث.

يمكن العثور على تطبيق خادم TCP في هذا المستودع https://github.com/rafaqelhodev/rlimit/ وفي القسم التالي سأناقش باختصار تنفيذ مجموعة الرمز المميز في golang.

تنفيذ دلو الرمز المميز

أعرض أدناه الأفكار الرئيسية وراء تنفيذ مجموعة الرموز المميزة. من فضلك، قم بإلقاء نظرة على https://github.com/rafaqelhodev/rlimit/ المستودع لفهم التنفيذ التفصيلي.

يتم التحكم في حد المعدل بشكل مركزي في بنية TokenBucket:

type TokenBucket struct {
    id           string
    mu           sync.Mutex
    tokens       int64
    maxTokens    int64
    refillPeriod int64
    cron         chan bool
    subs         []chan bool
}

يمكنك ملاحظة وجود خاصية فرعية في بنية TokenBucket. في الأساس، هذه عبارة عن مجموعة من المشتركين في مجموعة رموز مميزة: في كل مرة يتم فيها طلب رمز مميز من العميل، تتم إضافة العميل إلى مجموعة الرموز الفرعية ويتم إخطار العميل عند إضافة رمز مميز جديد إلى المجموعة.

عند بدء المجموعة، نحتاج إلى توفير الحد الأقصى لعدد الرموز المميزة التي يمكن أن تدعمها المجموعة (maxTokens) ومقدار الوقت الذي تتم فيه إضافة الرمز المميز إلى المجموعة (فترة إعادة التعبئة):

func newTokenBucket(id string, maxTokens int64, refillPeriod int64) *TokenBucket {
    bucket := &TokenBucket{
        id:           id,
        tokens:       0,
        maxTokens:    maxTokens,
        refillPeriod: refillPeriod,
        cron:         make(chan bool),
        subs:         make([]chan bool, 0),
    }
    fmt.Printf("refill period  = %d\n", refillPeriod)
    bucket.startCron()
    return bucket
}

الآن، قد تتساءل، "كيف تتم إضافة الرمز المميز إلى المجموعة؟". لذلك، عند إنشاء مجموعة، تبدأ مهمة cron، وفي كل ميلي ثانية من فترة إعادة التعبئة، تتم إضافة رمز مميز جديد إلى المجموعة:

func (tb *TokenBucket) startCron() {
    ticker := time.NewTicker(time.Duration(tb.refillPeriod) * time.Millisecond)

    go func() {
        for {
            select {
            case  0 {
                        sub := tb.subs[0]
                        tb.subs = tb.subs[1:]
                        sub 



أخيرًا، عندما يريد العميل رمزًا مميزًا من المجموعة، يجب استدعاء وظيفة الانتظار المتوفرة:

func (tb *TokenBucket) waitAvailable() bool {
    tb.mu.Lock()

    if tb.tokens > 0 {
        fmt.Printf("[CONSUMING TOKEN] - id = %s\n", tb.id)
        tb.tokens -= 1
        tb.mu.Unlock()
        return true
    }

    fmt.Printf("[WAITING TOKEN] - id %s\n", tb.id)

    ch := tb.tokenSubscribe()

    tb.mu.Unlock()

    





مستوحاة من https://github.com/Mohamed-khattab/Token-bucket-rate-limiter

بيان الافراج تم نشر هذه المقالة على: https://dev.to/rafaqelhodev/controlling-outgoing-rate-limit-3klg?1 إذا كان هناك أي انتهاك، يرجى الاتصال بـ [email protected] لحذفه
أحدث البرنامج التعليمي أكثر>

تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.

Copyright© 2022 湘ICP备2022001581号-3