«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Управление лимитом исходящей скорости

Управление лимитом исходящей скорости

Опубликовано 30 июля 2024 г.
Просматривать:192

Представим себе сценарий, в котором имеется распределенное приложение, взаимодействующее со сторонним API. Обычно сторонние API имеют механизм управления ограничением скорости, чтобы избежать пакетных запросов клиентов и простоев их служб. Как в таком случае вызывающая сторона может контролировать скорость исходящих запросов к стороннему API в распределенной среде? В этом посте обсуждается возможная стратегия решения этой проблемы.

Существует несколько алгоритмов управления скоростью запросов, но здесь мы сосредоточимся на алгоритме корзины токенов, поскольку его относительно легко понять и реализовать. Этот алгоритм гласит, что: корзина может содержать максимум T токенов, и когда приложение хочет сделать запрос к стороннему API, оно должно принять 1 жетон из ведра. Если корзина пуста, ей приходится ждать, пока в корзине не останется хотя бы 1 токен. Кроме того, корзина пополняется 1 токеном с фиксированной скоростью R токенов/миллисекунды.

Алгоритм корзины токенов очень прост для понимания, но как можно использовать его в распределенной среде для управления исходящими запросами к сторонним API?

Если кто-то хочет контролировать ограничение исходящей скорости в распределенной среде, необходим централизованный источник достоверных сведений о текущем ограничении скорости. Существует несколько способов реализации источника истины, и я идеализировал следующую диаграмму с возможной реализацией:

Controlling outgoing rate limit

На рисунке выше у нас есть распределенное приложение в нескольких модулях, и каждый модуль может отправлять запросы к стороннему API. В инфраструктуре приложения имеется TCP-сервер, который контролирует ограничение скорости с помощью алгоритма сегмента токенов. Прежде чем сделать запрос к стороннему API, модуль запрашивает у TCP-сервера новый токен и ожидает ответа от TCP-сервера до тех пор, пока не появится хотя бы один доступный токен. После того как токен доступен, модуль отправляет запрос к стороннему API.

Реализацию TCP-сервера можно найти в этом репозитории https://github.com/rafaquelhodev/rlimit/, а в следующем разделе я кратко обсужу реализацию корзины токенов в golang.

Реализация корзины токенов

Ниже я показываю основные идеи реализации корзины токенов. Пожалуйста, загляните в репозиторий https://github.com/rafaquelhodev/rlimit/, чтобы понять подробную реализацию.

Управление ограничением скорости централизовано в структуре TokenBucket:

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

Вы можете заметить, что в структуре TokenBucket есть свойство subs. По сути, это массив подписчиков для определенного сегмента токенов: каждый раз, когда токен запрашивается у клиента, клиент добавляется в массив subs, и клиент уведомляется, когда в корзину добавляется новый токен.

При запуске корзины нам необходимо указать максимальное количество токенов, которое может поддерживать корзина (maxTokens), а также время, в течение которого токен добавляется в корзину (refillPeriod):

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, и каждые миллисекунды refillPeriod в корзину добавляется новый токен:

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 



Наконец, когда клиент хочет получить токен из корзины, необходимо вызвать функцию waitAvailable:

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/rafaquelhodev/controlling-outgoing-rate-limit-3klg?1. В случае каких-либо нарушений, пожалуйста, свяжитесь с [email protected], чтобы удалить ее.
Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3