Откажитесь падать! Статья, подробно объясняющая схему ограничения распределенного тока (с реализацией кода)
Откажитесь падать! Статья, подробно объясняющая схему ограничения распределенного тока (с реализацией кода)
👉Введение

С ростом популярности микросервисов зависимости и отношения вызовов между сервисами становятся все более сложными, а стабильность сервисов становится особенно важной. Бизнес-сценарии часто включают в себя мгновенное воздействие на трафик, что может привести к тайм-аутам запросов и ответов или даже к перегрузке, отключению и недоступности сервера. Чтобы защитить саму систему, а также восходящие и нисходящие службы, мы обычно ограничиваем поток запросов и быстро отклоняем запросы, которые превышают верхний предел конфигурации, чтобы обеспечить стабильность системы или вышестоящих и нисходящих сервисных систем. Разумные стратегии могут эффективно справляться с последствиями дорожного движения и обеспечивать доступность и производительность системы. В этой статье подробно представлены несколько алгоритмов ограничения тока, сравниваются преимущества и недостатки каждого алгоритма, даются некоторые предложения по выбору алгоритмов ограничения тока, а также предлагаются некоторые решения для ограничения распределенного тока, обычно используемые в бизнесе.

Хорошая конструкция ограничения тока должна учитывать характеристики и потребности бизнеса и иметь следующие шесть пунктов:

  1. Многоуровневое ограничение тока:Помимо основного и резервногокопироватьтекущий предел Служить,Вы можете рассмотреть возможность реализации многоуровневой стратегии ограничения тока. Например,Ограничение тока можно установить на уровне приложения, уровне обслуживания и уровне данных.,Это обеспечивает лучшую защиту от перегрузки.
  2. Динамическая регулировка порога:мы можем основываться насистема Динамически корректируйте текущую стратегию ограничения на основе условий нагрузки в реальном времени.。Например,Когда нагрузка на систему низкая,Мы можем ослабить текущую политику ограничения, когда нагрузка высока;,Мы можем ужесточить текущую ограничительную политику.
  3. Гибкие размеры:Текущие стратегии ограничения должны иметь возможность корректироваться в соответствии с различными бизнес-сценариями.。Помимо интерфейса,оборудование,ip,Счет id Помимо равных размеров, мы также можем рассмотреть более мелкозернистое ограничение тока. Например, мы можем ограничить трафик на основе моделей поведения пользователей, что позволит лучше предотвращать атаки злоумышленников.
  4. Развязка:В качестве основы следует использовать ограничение тока.Служить,Отдельно от конкретной бизнес-логики. так,Когда меняется бизнес-логика,Нет необходимости изменять код ограничения тока.,Просто скорректируйте текущую ограничивающую стратегию.
  5. Отказоустойчивость:Ограничение тока Служить Должен быть высокодоступным,Но если что-то пойдет не так,У бизнеса должны быть альтернативы (выключатель, понижение рейтинга). Это может включать использование альтернативного ограничения тока.,Или решите, следует ли отклонить запрос, исходя из конфиденциальности бизнеса.
  6. Мониторинг и тревожная сигнализация:верно Ограничение тока Стратегии следует отслеживать в режиме реального времени.,И настроить механизм сигнализации. Когда срабатывает текущая политика ограничения,Получайте оповещения немедленно,Чтобы мы могли решить проблему вовремя.

01. Фон

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

  1. кэш:кэш Это технология, улучшающая производительность чтения данных.,Сохраняя часто используемые данные в памяти,может уменьшитьбаза данныхили Другое хранилищесистемапосещать,Тем самым улучшая скорость реакции системы. Кэширование может применяться на нескольких уровнях.,Например Браузеркэш、CDN Кэширование, кэширование обратного прокси-сервера, кэширование приложений и т. д.
  2. Понижение рейтинга: Понижение рейтинга происходит в случае чрезмерного давления и отсутствия детали Служить,Временно закрыть некоторые непрофильные Служить,Для обеспечения нормальной работы активной зоны Служить. Понижение рейтинга может происходить на нескольких уровнях,Например Понижение страницы、Функция понижения версии、Служитьпонижение рейтинга и т. д.。
  3. Ограничение тока. Ограничение тока — это технология, которая контролирует скорость, с которой система обрабатывает запросы.,Во избежание перегрузки системы. Ограничение тока может быть достигнуто с помощью различных алгоритмов.,Напримерведро жетоновалгоритм、Метод дырявого ствола и так далее.

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

02. Обзор текущих ограничивающих знаний

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

При ограничении тока необходимо понимать две важные концепции:

  1. Порог:Относится к количеству запросов, разрешенных в единицу времени.。Например,Ограничьте количество запросов в секунду (запросов в секунду) до 500.,Указывает, что в течение 1 секунды может быть принято максимум 500 запросов. Устанавливая соответствующие пороговые значения,Может контролировать нагрузку системы,Избегайте слишком большого количества запросов, которые могут привести к сбою системы или снижению производительности.
  2. Политика запрета:Политики обработки запросов, превышающих пороговые значения。Общие стратегии отказа включают в себяОткажитесь напрямую и ждите в очередиждать。Прямой отказ немедленно отклоняет запросы, превышающие пороговое значение.,Очередь и ожидание помещают запрос в очередь,Обработка по определенным правилам. Выбор подходящей стратегии отклонения может сбалансировать стабильность системы и удобство использования.

Устанавливая разумные пороговые значения и выбирая соответствующие стратегии отклонения, технология ограничения тока может помочь системе справиться с внезапными скачками объема запросов, злонамеренным доступом пользователей или чрезмерной частотой запросов, обеспечивая стабильность и доступность системы. Схемы ограничения тока можно разделить на Ограничение тока одной машины и ограничение распределенного тока;Чтосередина Автономный Ограничение токав соответствии салгоритм,также можно разделить на фиксированное окно、раздвижное окно, дырявая бочка и ведро жетонов токоограничивающий и другие четыре распространенных типа。本文将верно上述Ограничение тока План представлен подробно。

03. Базовый алгоритм ограничения тока

3.1 Фиксированное ограничение тока окна

3.1.1 Введение в алгоритм

Алгоритм фиксированного окна — это простой и интуитивно понятный алгоритм ограничения тока. Его принцип состоит в том, чтобы разделить время на окна фиксированного размера и ограничить количество или скорость запросов в каждом окне. В конкретной реализации счетчик может использоваться для записи количества запросов в текущем окне и сравнения его с заданным пороговым значением. Принцип алгоритма фиксированного окна заключается в следующем:

  1. Разделите время на окна фиксированного размера, например одно окно в секунду.
  2. В каждом окне фиксируется количество запросов.
  3. При поступлении запроса счетчик запросов увеличивается на единицу.
  4. Если количество запросов превышает заданный порог (например, 3 запроса), отклоните запрос.
  5. После закрытия окна счетчик запросов сбрасывается.

3.1.2 Реализация кода

Язык кода:javascript
копировать
type FixedWindowLimiter struct {
   windowSize  time.Duration // размер окна
   maxRequests int           // Максимальное количество запросов
   requests    int           // Количество запросов в текущем окне
   lastReset   int64         // Время сброса последнего окна (метка времени второго уровня)
   resetMutex  sync.Mutex    // сбросить блокировку
}

func NewFixedWindowLimiter(windowSize time.Duration, maxRequests int) *FixedWindowLimiter {
   return &FixedWindowLimiter{
      windowSize:  windowSize,
      maxRequests: maxRequests,
      lastReset:   time.Now().Unix(),
   }
}

func (limiter *FixedWindowLimiter) AllowRequest() bool {
   limiter.resetMutex.Lock()
   defer limiter.resetMutex.Unlock()

   // Проверьте, нужно ли сбросить окно
   if time.Now().Unix()-limiter.lastReset >= int64(limiter.windowSize.Seconds()) {
      limiter.requests = 0
      limiter.lastReset = time.Now().Unix()
   }

   // Проверьте, превышает ли количество запросов порог
   if limiter.requests >= limiter.maxRequests {
      return false
   }

   limiter.requests++
   return true
}

func main() {
   limiter := NewFixedWindowLimiter(1*time.Second, 3) // Разрешить до 3 запросов в секунду
   for i := 0; i < 15; i++ {
      now := time.Now().Format("15:04:05")
      if limiter.AllowRequest() {
         fmt.Println(now + " Запрос через ")
      } else {
         fmt.Println(now + " Запросы ограничиваются")
      }
      time.Sleep(100 * time.Millisecond)
   }
}

Результат выполнения:

3.1.3 Преимущества и недостатки

преимущество:

  1. Просто реализовать: фиксированное Реализация оконного алгоритма относительно проста, ее легко понять и развернуть.
  2. Более высокая стабильность: пакетные запросы можно лучше ограничивать и контролировать, а стабильность выше.
  3. Простота реализации контроля нормы: фиксированное Оконныйалгоритм позволяет легко ограничить скорость запросов, например количество разрешенных запросов в секунду.

недостаток:

  1. Неравномерное распределение запросов: фиксированное окноалгоритмсередина,Распределение запросов внутри окна может быть неравномерным,Приводит к тому, что количество запросов в определенных окнах превышает пороговое значение.,В других окнах запросов меньше.
  2. Невозможно справиться с чрезвычайными ситуациями: фиксированное окноалгоритмизразмер окнафиксированоиз,Неспособность гибко реагировать на чрезвычайные ситуации.
  3. Нечестность запроса. Сброс счетчика запросов в конце окна может привести к несправедливости запроса. Например, в последнюю секунду перед завершением окна счетчик запросов полон, а в первую секунду в начале окна счетчик запросов равен нулю.

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

3.2 Ограничение тока скользящего окна

3.2.1 Знакомство с алгоритмом

Выше было объяснено, что при возникновении критических изменений во временном окне алгоритм фиксированного окна может оказаться неспособным гибко реагировать на изменения в трафике. Например, если в конце временного окна внезапно появляется большое количество запросов, алгоритм фиксированного окна может привести к отклонению запросов, даже если в следующем временном окне запросов не так много. В этом случае нам нужен более гибкий алгоритм для борьбы с пакетным трафиком и неравномерным распределением запросов — алгоритм скользящего окна. Этот алгоритм является усовершенствованием алгоритма фиксированного окна, который динамически регулирует размер окна, чтобы лучше адаптироваться к изменениям трафика. В отличие от алгоритма фиксированного окна, алгоритм скользящего окна может регулировать размер окна перед появлением следующего временного окна, чтобы лучше контролировать скорость запросов. Принцип алгоритма следующий:

  1. Размер окна: определите фиксированный размер окна, например 1 секунду.
  2. Счетчик запросов: внутри окна каждый раз, когда поступает запрос, счетчик запросов увеличивается на 1.
  3. Условия ограничения: Если количество запросов в окне превышает установленный порог, то есть превышает максимально разрешенное количество запросов, запрос будет отклонен.
  4. Скольжение окна: со временем окно будет продолжать смещаться, удаляя счетчики просроченных запросов, чтобы количество запросов в окне оставалось в пределах лимита.
  5. Динамическая регулировка: в раздвижном окноалгоритмсередина,Мы можем настроить размер окна в соответствии с реальной ситуацией. прежде чем встретить следующее временное окно,Мы можем изменить размер окна в соответствии с текущей ситуацией с потоком.,Адаптироваться к изменениям потока.

3.2.2 Реализация кода

Язык кода:javascript
копировать
package main

import (
   "fmt"
   "sync"
   "time"
)

type SlidingWindowLimiter struct {
   windowSize   time.Duration // размер окна
   maxRequests  int           // Максимальное количество запросов
   requests     []time.Time   // Время запроса в пределах окна
   requestsLock sync.Mutex    // запросить блокировку
}

func NewSlidingWindowLimiter(windowSize time.Duration, maxRequests int) *SlidingWindowLimiter {
   return &SlidingWindowLimiter{
      windowSize:  windowSize,
      maxRequests: maxRequests,
      requests:    make([]time.Time, 0),
   }
}

func (limiter *SlidingWindowLimiter) AllowRequest() bool {
   limiter.requestsLock.Lock()
   defer limiter.requestsLock.Unlock()

   // Удалить запросы с истекшим сроком действия
   currentTime := time.Now()
   for len(limiter.requests) > 0 && currentTime.Sub(limiter.requests[0]) > limiter.windowSize {
      limiter.requests = limiter.requests[1:]
   }

   // Проверьте, превышает ли количество запросов порог
   if len(limiter.requests) >= limiter.maxRequests {
      return false
   }

   limiter.requests = append(limiter.requests, currentTime)
   return true
}

func main() {
   limiter := NewSlidingWindowLimiter(500*time.Millisecond, 2) // Разрешить до 4 запросов в секунду
   for i := 0; i < 15; i++ {
      now := time.Now().Format("15:04:05")
      if limiter.AllowRequest() {
         fmt.Println(now + " Запрос через ")
      } else {
         fmt.Println(now + " Запросы ограничиваются")
      }
      time.Sleep(100 * time.Millisecond)
   }
}

Результат выполнения:

3.2.3 Преимущества и недостатки

преимущество:

  1. Гибкость: алгоритм раздвижного окна может динамически регулировать размер окна в соответствии с реальной ситуацией.,Адаптироваться к изменениям потока.Эта гибкость позволяеталгоритм Будьте способны лучше справляться с чрезвычайными ситуациямипотоки неравномерное распределение запросовиз Состояние。
  2. Реальное время: благодаря раздвижному оконныйалгоритм выполняет скольжение окна в конце каждого временного окна,Он может быстрее реагировать на изменения потока.,Обеспечивает более эффект ограничения тока в реальном времени.
  3. Точность: по сравнению с фиксированным окноалгоритм,Раздвижное окноалгоритм имеет меньший размер частиц,Может обеспечить более точный контроль ограничения тока.

недостаток:

  1. Потребление памяти: раздвижное Алгоритм окна должен поддерживать время запроса в пределах окнасписок,через некоторое время,Длина списка будет увеличиваться. Это может привести к большему потреблению памяти.,особенно вразмер окна Больше или чаще запрашиваетсяиз Состояние下。
  2. сложность алгоритма: по сравнению с простотой фиксированное окноалгоритм,Реализация раздвижного оконного алгоритма более сложна. Ему необходимо обрабатывать такую ​​логику, как скольжение окон, подсчет запросов и удаление просроченных запросов.,Может потребоваться больше кода и вычислительных затрат.

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

3.3 Ограничение тока утечки ведра

3.3.1 Знакомство с алгоритмом

хотяраздвижное Оконныйалгоритм может обеспечить определенный эффект ограничения потока, но он по-прежнему ограничен размером окна и временным интервалом. В некоторых случаях пакет может привести к превышению лимита количества запросов в окне. Для лучшего сглаживания потока требуется Ограничение тока дырявого ведраалгоритма может быть использовано как усовершенствование алгоритма раздвижного окна. Принцип алгоритма прост: он поддерживает дырявое ведро с фиксированной емкостью.,Запросы попадают в дырявое ведро с переменной скоростью.,Дырявое ведро вытекает с фиксированной скоростью. Если запрос поступил,Дырявое ведро полно,но Политика запрета будет активирована。Можно получить измодель производитель-потребительчтобы понять этоалгоритм,Просьба выступить в роли продюсера,Каждая просьба как капля воды,когда поступит запрос,Он ставится в очередь (дырявое ведро) середина, а дырявое ведро выступает в роли потребителя.,Потребляйте запросы из очереди с фиксированной скоростью.,Как вода, капающая из дырок на дне бочки. Скорость потребления равна порогу ограничения тока,Например, обрабатывать 2 запроса в секунду.,То есть на обработку одного запроса уходит 500 миллисекунд. Утечка емкости ковшакак очередьиземкость,Когда количество запросов превышает указанную емкость,Политика запрета будет активирована,То есть вновь поступающие запросы будут отбрасываться или задерживаться. Реализация алгоритма следующая:

  1. Емкость дырявого сегмента. Определите фиксированную емкость дырявого сегмента, которая представляет собой максимальное количество запросов, которые может хранить дырявый сегмент.
  2. Скорость «дырявого» ведра. Определите фиксированную скорость «дырявого» ведра, которая представляет собой количество запросов, которые «дырявое» ведро может обработать в секунду.
  3. Обработка запроса. Когда запрос поступает, производитель помещает его в «дырявое ведро».
  4. Отток из дырявой корзины. Дырявая корзина принимает запросы из дырявой корзины с фиксированной скоростью и обрабатывает эти запросы. Если в дырявой корзине есть запрос, запрос обрабатывается, если дырявая корзина пуста, запрос не обрабатывается;
  5. Отмена запроса или задержка. Если дырявый контейнер заполнен, то есть количество запросов в дырявом сегменте достигает предела емкости, новые поступающие запросы будут отброшены или задержаны.

3.3.2 Реализация кода

Язык кода:javascript
копировать
package main

import (
   "fmt"
   "time"
)

type LeakyBucket struct {
   rate       float64 // Частота дырявого сегмента, количество запросов в секунду
   capacity   int     // Емкость дырявого сегмента, максимальное количество запросов, которые можно сохранить.
   water      int     // Текущий объем воды указывает количество запросов в текущем дырявом ведре.
   lastLeakMs int64   // Временная метка последней утечки воды, в секундах
}

func NewLeakyBucket(rate float64, capacity int) *LeakyBucket {
   return &LeakyBucket{
      rate:       rate,
      capacity:   capacity,
      water:      0,
      lastLeakMs: time.Now().Unix(),
   }
}

func (lb *LeakyBucket) Allow() bool {
   now := time.Now().Unix()
   elapsed := now - lb.lastLeakMs

   // Утечка воды, рассчитайте количество утекшей воды в зависимости от временного интервала.
   leakAmount := int(float64(elapsed) / 1000 * lb.rate)
   if leakAmount > 0 {
      if leakAmount > lb.water {
         lb.water = 0
      } else {
         lb.water -= leakAmount
      }
   }

   // Определите, превышает ли текущий объем воды емкость
   if lb.water > lb.capacity {
      lb.water-- // Если емкость превышена, вычтите количество только что добавленной воды.
      return false
   }

   // увеличить объем воды
   lb.water++

   lb.lastLeakMs = now
   return true
}

func main() {
   // Создайте дырявое ведро со скоростью 3 запроса в секунду и емкостью 4 запроса.
   leakyBucket := NewLeakyBucket(3, 4)

   // Запрос на моделирование
   for i := 1; i <= 15; i++ {
      now := time.Now().Format("15:04:05")
      if leakyBucket.Allow() {
         fmt.Printf(now+"  Нет. %d запросы переданы\n", i)
      } else {
         fmt.Printf(now+"  Нет. %d запросы ограничены\n", i)
      }
      time.Sleep(200 * time.Millisecond) // Запрос на моделированиеинтервал
   }
}

Результат выполнения:

3.3.3 Преимущества и недостатки

преимущество:

  1. Сглаживание потока: алгоритм «Дырявый ствол» может сгладить внезапный поток.,Сделайте выходной поток более стабильным,Избегается влияние внезапного увеличения потока на систему.
  2. Просто и легко реализовать: Принцип дырявого ведра прост и относительно легко реализуем.
  3. Эффективная защита от перегрузки: за счет контроля оттока потока,Негерметичные бочки могут эффективно предотвратить перегрузку.

недостаток:

  1. Недостаточно гибок, чтобы справиться с внезапным потоком: хотя алгоритм дырявого ведра может сгладить внезапный поток.,Но в некоторых случаях,Возможно, мы хотим иметь возможность быстро реагировать на чрезвычайные ситуации. в этом случае,Метод дырявого ведра может оказаться недостаточно гибким.
  2. Невозможно динамически регулировать поток: скорость оттока в алгоритме дырявого ведра фиксирована и не может быть динамически отрегулирована в соответствии с фактической ситуацией в системе.
  3. Может привести к потере потока: если входной поток меньше скорости оттока из дырявого ведра, то скорость оттока из дырявого ведра будет потрачена впустую.
  4. Если входной поток постоянно превышает скорость оттока из дырявого ведра,Тогда дырявое ведро всегда будет полным.,Новые запросы будут отклонены.,Может привести к снижению качества Служить.

3.4 Ограничение тока корзины токенов

3.4.1 Знакомство с алгоритмом

Алгоритм ведра токенов — это распространенная идея реализации ограничения тока, которая используется для ограничения скорости запросов. Это гарантирует, что система по-прежнему сможет предоставлять стабильные услуги в условиях высокой нагрузки, и предотвращает перегрузку системы пакетным трафиком. Текущий класс инструмента ограничения RateLimiter в наиболее часто используемом наборе инструментов разработки Google Java Guava представляет собой реализацию корзины токенов. Алгоритм корзины токенов основан на концепции корзины токенов, где токены генерируются с фиксированной скоростью и помещаются в корзину. Каждый токен представляет запрошенное разрешение. Когда поступает запрос, для его передачи необходимо получить токен из корзины токенов. Если в корзине токенов недостаточно токенов, запрос регулируется или отбрасывается. Шаги реализации алгоритма корзины токенов следующие:

  1. Инициализировать ведро жетонов,включатьемкость ковшаи генерация токеновизставка。
  2. Постоянно генерировать токены по фиксированной ставке,и вставь ведро жетонов,пока ведро не наполнится.
  3. когда поступит запрос,попробуй начать сведро Получите жетон в жетонах.
  4. есливедро Если в жетонах достаточно токенов, запрос проходит и начинается с ведро. Удалите жетон из жетонов.
  5. есливедро В жетонах недостаточно токенов и запрос дросселируется или отбрасывается.

3.4.2 Реализация кода

Язык кода:javascript
копировать
package main

import (
   "fmt"
   "sync"
   "time"
)

// TokenBucket означает ведро жетонов。
type TokenBucket struct {
   rate       float64    // Скорость, с которой токены добавляются в корзину.
   capacity   float64    // Максимальная вместимость ковша.
   tokens     float64    // Количество токенов, находящихся в данный момент в корзине.
   lastUpdate time.Time  // Время последнего обновления суммы токена.
   mu         sync.Mutex // Блокировка мьютекса для обеспечения потокобезопасности.
}

// NewTokenBucket Создать новое ведро жетонов, учитывая скорость добавления жетонов и емкость ведра.
func NewTokenBucket(rate float64, capacity float64) *TokenBucket {
   return &TokenBucket{
      rate:       rate,
      capacity:   capacity,
      tokens:     capacity, // Изначально ведро полное.
      lastUpdate: time.Now(),
   }
}

// Allow Проверьте, можно ли удалить токен из корзины. Если это возможно, он удаляет токен и возвращает true。
// Если нет, он возвращает false。
func (tb *TokenBucket) Allow() bool {
   tb.mu.Lock()
   defer tb.mu.Unlock()

   // Рассчитайте количество токенов, которые нужно добавить, исходя из затраченного времени.
   now := time.Now()
   elapsed := now.Sub(tb.lastUpdate).Seconds() 
   tokensToAdd := elapsed * tb.rate            

   tb.tokens += tokensToAdd
   if tb.tokens > tb.capacity {
      tb.tokens = tb.capacity // Убедитесь, что количество жетонов не превышает вместимости корзины.
   }

   if tb.tokens >= 1.0 {
      tb.tokens--
      tb.lastUpdate = now
      return true
   }

   return false
}

func main() {
   tokenBucket := NewTokenBucket(2.0, 3.0)

   for i := 1; i <= 10; i++ {
      now := time.Now().Format("15:04:05")
      if tokenBucket.Allow() {
         fmt.Printf(now+"  Нет. %d запросы переданы\n", i)
      } else { // Если токен невозможно удалить, запрос отклоняется.
         fmt.Printf(now+"  Нет. %d запросы ограничены\n", i)
      }
      time.Sleep(200 * time.Millisecond)
   }
}

Результат выполнения:

3.4.3 Преимущества и недостатки

преимущество:

  1. Плавный поток: ведро жетоновалгоритм может сгладить внезапный поток.,Сделайте всплески потока равномерно распределенными в течение определенного периода времени.,Избегается влияние внезапного пика потока на систему.
  2. Гибкость: ведро жетоновалгоритм можно гибко контролировать, регулируя скорость генерации токенов и размер корзины.
  3. Разрешить внезапный поток: из-за ведро жетонов Можно накопить определенную суммуизжетон,Поэтому, когда поток внезапно увеличивается,Если в ведре достаточно жетонов,С такими чрезвычайными ситуациями может справиться поток.

недостаток:

  1. Сложная реализация: по сравнению с некоторыми другими методами ограничения тока (например, дырявым ковшом).,Реализация ведро жетоновалгоритма немного сложнее.,Необходимо поддерживать генерацию и потребление токенов.
  2. Нужен точный контроль времени: ведро жетоновалгоритм Необходимо генерировать токены в зависимости от времени,Поэтому необходим точный контроль времени. Если контроль времени системы неточный,Это может повлиять на эффект ограничения тока.
  3. Возможна пустая трата ресурсов: если поток системы продолжает быть ниже скорости генерации токенов,Тогда токены в ведре могут продолжать накапливаться.,Вызывает бесполезную трату ресурсов.

3.5 Сравнение четырех основных алгоритмов

алгоритм

преимущество

недостаток

Подходит для сцены

фиксированное окно

Простой и интуитивно понятный, легко реализуемый. Подходит для стабильного контроля расхода и простого в реализации контроля скорости.

Неспособность справиться с всплеском трафика за короткий период времени. Неравномерный трафик может привести к всплеску трафика.

Стабильный контроль потока, отсутствие необходимости обеспечивать равномерное распределение запросов

раздвижное окно

Плавная обработка пакетного трафика имеет меньшую степень детализации и может обеспечить более точное управление ограничением тока.

Реализация относительно сложна и требует поддержания состояния раздвижного окна, что приводит к высокому потреблению памяти.

Сценарии, требующие плавной обработки пакетного трафика.

утечкаведроалгоритм

Плавная обработка пакетного трафика позволяет зафиксировать скорость вывода и эффективно предотвратить перегрузку.

Обработка пакетного трафика недостаточно гибка, чтобы справляться с колебаниями трафика.

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

ведро жетонов

Плавно обрабатывайте всплеск трафика и динамически настраивайте текущие правила ограничения, чтобы адаптироваться к изменениям трафика в различные периоды времени.

Реализация относительно сложна и требует поддержания состояния ведро жетонов.

Сценарии, требующие динамической корректировки действующих ограничивающих правил.

04. Распределенное ограничение тока

Ограничение тока одной машины относится к ситуации одного Служить,За счет ограничения количества запросов, обрабатываемых одним сервером Служить в единицу времени.,Не допускайте перегрузки устройства «Служить». Общие методы ограничения тока были представлены выше.,Его преимущество заключается в простоте реализации.,Высокая эффективность,Эффект очевиден. С популярностью микро-Служить,Служить системы обычно развертывается на нескольких серверах Служить.,В это время необходимо ограничить ток, чтобы обеспечить стабильность всей системы. В следующей статье будут представлены несколько распространенных технологических решений распределенного ограничения тока:

4.1 Централизованное решение для ограничения тока

4.1.1 Принцип плана

Все запросы к серверу контролируются через централизованный ограничитель потока. Метод реализации:

  1. Выберите централизованный компонент, например Redis.
  2. Определите текущие правила ограничения. Например, вы можете установить максимальное количество разрешенных запросов в секунду (QPS) и сохранить это значение в Redis.
  3. Для каждого запроса серверу Служить необходимо сначала отправить запрос к Redis Запросить токен.
  4. Если токен получен, это означает, что запрос может быть обработан; если токен не получен, это означает, что запрос ограничен, и вы можете вернуть сообщение об ошибке или повторить попытку позже.

4.1.2 Реализация кода

Язык кода:javascript
копировать
package main

import (
   "context"
   "fmt"
   "go.uber.org/atomic"
   "sync"

   "git.code.oa.com/pcg-csd/trpc-ext/redis"
)

type RedisClient interface {
   Do(ctx context.Context, cmd string, args ...interface{}) (interface{}, error)
}

// Client база данных
type Client struct {
   client RedisClient // redis действовать
   script string      // Lua-скрипт
}

// NewBucketClient Создать редисведро жетонов
func NewBucketClient(redis RedisClient) *Client {
   helper := redis
   return &Client{
      client: helper,
      script: `
         -- ведро жетонов скрипт ограничения тока
         -- KEYS[1]: имя сегмента
         -- ARGV[1]: емкость ковша
         -- ARGV[2]: Скорость генерации токенов
         
         local bucket = KEYS[1]
         local capacity = tonumber(ARGV[1])
         local tokenRate = tonumber(ARGV[2])
         
         local redisTime = redis.call('TIME')
         local now = tonumber(redisTime[1])
         
         local tokens, lastRefill = unpack(redis.call('hmget', bucket, 'tokens', 'lastRefill'))
         tokens = tonumber(tokens)
         lastRefill = tonumber(lastRefill)
         
         if not tokens or not lastRefill then
            tokens = capacity
            lastRefill = now
         else
            local intervalsSinceLast = (now - lastRefill) * tokenRate
            tokens = math.min(capacity, tokens + intervalsSinceLast)
         end
         
         if tokens < 1 then
            return 0
         else
            redis.call('hmset', bucket, 'tokens', tokens - 1, 'lastRefill', now)
            return 1
         end
      `,
   }
}

// Получите токен. Если приобретение прошло успешно, он немедленно вернет true, в противном случае — false.
func (c *Client) isAllowed(ctx context.Context, key string, capacity int64, tokenRate int64) (bool, error) {
   result, err := redis.Int(c.client.Do(ctx, "eval", c.script, 1, key, capacity, tokenRate))
   if err != nil {
      fmt.Println("Redis Ошибка выполнения: ", err)
      return false, err
   }
   return result == 1, nil
}

// обнаружение звонков
func main() {
   c := NewBucketClient(redis.GetPoolByName("redis://127.0.0.1:6379"))
   gw := sync.WaitGroup{}
   gw.Add(120)
   count := atomic.Int64{}
   for i := 0; i < 120; i++ {
      go func(i int) {
         defer gw.Done()
         status, err := c.isAllowed(context.Background(), "test", 100, 10)
         if status {
            count.Add(1)
         }
         fmt.Printf("go %d status:%v error: %v\n", i, status, err)
      }(i)
   }
   gw.Wait()
   fmt.Printf("allow %d\n\n", count.Load())
}

Результат выполнения:

4.1.3 Существующие проблемы

  1. Узкое место в производительности: поскольку все запросы должны проходить Редис, поэтому Redis Это может стать узким местом производительности всей системы. Чтобы решить эту проблему, рассмотрите возможность использования Redis Кластер для повышения производительности или использования более производительного оборудования.
  2. Единая точка отказа: если Redis В случае неисправности будет затронута функция ограничения тока всей системы. Чтобы решить эту проблему, рассмотрите возможность использования Redis Режим «главный-подчиненный копировать или дозорный» используется для достижения высокой доступности.
  3. Пропускная способность сети. Redis — это база данных в памяти, основанная на сетевом обмене данными, поэтому пропускная способность сети является ключевым фактором ее производительности. Если пропускная способность сети ограничена, это может привести к снижению скорости передачи запроса, что повлияет на производительность Redis.

4.2 Распределенное решение по ограничению тока на основе балансировки нагрузки

4.2.1 Принцип плана

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

  1. использовать балансировщик нагрузки или распределенный Служить обнаружение (Polaris может это сделать),Распределяйте запросы равномерно на каждую машину. Это гарантирует, что каждая машина сможет обработать часть запросов.
  2. Поддерживайте локальный статус ограничения тока на каждой машине.,реализовать местныекэш Автономный Ограничение токаизлогика。использоватьведро жетоновалгоритм, токоограничивающее управление осуществляется независимо на каждой машине. Количество запросов, обрабатываемых в секунду, ведро Количество жетонов для жетонов и т.д. На основании локального статуса ограничения тока выносится решение об ограничении тока по входящим запросам.
  3. Подготовьте соответствующий план динамической регулировки, чтобы динамически регулировать параметры ограничения тока в соответствии с фактической нагрузкой каждой машины. Например, если загрузка ЦП или памяти компьютера слишком высока, вы можете снизить порог регулирования компьютера, чтобы уменьшить количество запросов, обрабатываемых компьютером. Напротив, если использование ресурсов машиной низкое, увеличьте порог ограничения тока машины и увеличьте мощность обработки запросов машины.

4.2.2 Проблемы

  1. Локальный кэш. Это решение предъявляет высокие требования к локальному кэшу. Вам необходимо определить стратегию устранения локального кэша, а также ограничения на емкость кэша и другие точки риска на основе бизнес-логики.
  2. Ограничение тока Точность:местныйкэш Автономный Ограничение токаиз Точность受限于每个Служить Примериз Ресурсы и конфигурация。Это может привести к Ограничение тока Стратегия не может точно соответствовать всемсистемаизпотокизменять,Действующие правила ограничения не могут гибко корректироваться.
  3. Единая точка отказа для балансировщика нагрузки запросов.
  4. Адаптивность динамического расширения и сжатия: когда системе необходимо динамически расширять или уменьшать емкость.,Это решение может потребовать дополнительной настройки и корректировок.,Чтобы гарантировать, что вновь добавленные или удаленные экземпляры Служить могут правильно участвовать в текущем ограничении и запросить балансировку.

4.3 Ограничение тока на основе службы распределенной координации

4.3.1 Принцип схемы

Используйте службы распределенной координации, такие как ZooKeeper или etcd, для реализации ограничения тока. Каждый сервер подает заявку на получение токена от службы распределенной координации, и обрабатываться могут только те запросы, которые получают токен. Базовый план:

  1. Инициализировать ведро жетонов: у ZooKeeper Создайте узел в , данные узла представляют количество токенов. Изначально установите данные ведро Емкость жетонов.
  2. Подать заявку на токен: при поступлении запроса,Сервер Служить сначала подает заявку на токен от ZooKeeper. Это можно сделать, получив распределенную блокировку узла.,Затем добавьте узелиз Данные минус1выполнить。еслидействоватьуспех,Это означает, что токен подан на,Запрос может быть обработан;еслидействоватьнеудача,Указывает, что токен израсходован.,Запрос нужно отклонить и подождать.
  3. Токен выпуска: при обработке запроса,Серверу необходимо передать токен ZooKeeper. Это можно сделать, получив распределенную блокировку узла.,Затем добавьте 1 к данным узла, чтобы добиться этого.
  4. Дополнительный токен: вы можете настроить запланированную задачу для регулярной отправки ZooKeeper серединаизведро жетонов Дополнительный токен. Частота и количество пополнений могут динамически регулироваться в зависимости от условий нагрузки системы.

4.3.2 Проблемы

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

05. Резюме

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

Ограничение тока является важным средством обеспечения стабильной и эффективной работы системы, но не единственным решением.我们还需要考虑Что他изсистема Инструменты проектирования и оптимизации,Например, балансировка нагрузки, кэширование, асинхронная обработка и т. д. (в условиях взрывного объема,Расширение – всегда лучший способ,Вот только это дорого! ). Эти средства работают вместе,Чтобы построить систему, способную обрабатывать большое количество одновременных запросов,И можем гарантировать качество Служить системы.

-End-

Автор оригинала|Чэнь Дайфу

boy illustration
13. Springboot интегрирует Protobuf
boy illustration
Примечание. Инструмент управления батареями Dell Dell Power Manager
boy illustration
Общая интерпретация класса LocalDate [java]
boy illustration
[Базовые знания ASP.NET Core] -- Веб-API -- Создание и настройка веб-API (1)
boy illustration
Настоящий бой! Подключите Passkey к своему веб-сайту для безопасного входа в систему без пароля.
boy illustration
Руководство по настройке Nginx: как найти, интерпретировать и оптимизировать настройки Nginx в Linux
boy illustration
Typecho отображает использование памяти сервера
boy illustration
Как вставить элемент перед указанным ключом в ассоциативный массив в PHP
boy illustration
swagger2 экспортирует API как текстовый документ (реализация Java) [легко понять]
boy illustration
Выбор фреймворка nodejs Express koa egg MidwayJS сравнение NestJS
boy illustration
Руководство по загрузке, установке и использованию SVN «Рекомендуемая коллекция»
boy illustration
Интерфейс PHPforwarding_php отправляет запрос на получение
boy illustration
Создавайте и защищайте связь в реальном времени с помощью SignalR и Azure Active Directory.
boy illustration
ВичатПубличная платформаразвивать(три)——ВичатQR-кодгенерировать&Сканировать кодсосредоточиться на
boy illustration
[Углубленное понимание Java IO] Используйте InputStreamReader для чтения содержимого файла и легкого выполнения задач преобразования текста.
boy illustration
сравнение строк PHP
boy illustration
9 сценариев асинхронного сбоя @Async
boy illustration
Эффективная обработка запланированных задач: углубленное изучение секретов библиотеки APScheduler на Python
boy illustration
Рекомендации по облегченному артефакту развязки внутренних компонентов Spring Event (событие Spring)
boy illustration
Go: Лесоруб-лесоруб на колесах Введение
boy illustration
Основы серверной разработки: технология кэширования, которую должен освоить каждый программист
boy illustration
Java Advanced Collections TreeSet: что это такое и зачем его использовать?
boy illustration
Оказывается, у команды go build столько знаний
boy illustration
Node.js
boy illustration
Анализ исходного кода, связанный с запланированными задачами версии ruoyi-vue (7), то есть анализ модуля ruoyi-quartz.
boy illustration
Вход в систему с помощью скан-кода WeChat (1) — объяснение процесса входа в систему со скан-кодом, получение авторизованного QR-кода для входа.
boy illustration
HikariPool-1 — обнаружено отсутствие потока или скачок тактовой частоты, а также конфигурация источника данных Hikari.
boy illustration
Сравнение высокопроизводительной библиотеки JSON Go
boy illustration
Простое руководство по извлечению аудио с помощью FFmpeg
boy illustration
Подсчитайте количество строк кода в проекте