Исследование и практика схемы ограничения распределенного тока
Исследование и практика схемы ограничения распределенного тока
Автор: павелхен

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

1 фон

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

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

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

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

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

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

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

Устанавливая разумные пороговые значения и выбирая соответствующие стратегии отклонения, технология ограничения тока может помочь системе справиться с внезапными скачками объема запросов, злонамеренным доступом пользователей или чрезмерной частотой запросов, обеспечивая стабильность и доступность системы. Схемы ограничения тока можно разделить на Ограничение тока одной машины и ограничение распределенного тока Среди них алгоритм ограничения тока отдельной машины можно разделить на; Существует четыре распространенных типа: фиксированное окно, скользящее окно, дырявое ведро и ограничение тока ведра токенов. . В этой статье будет подробно представлена ​​описанная выше схема ограничения тока.

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

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. Сглаживание потока: алгоритм Leaky Bucket может сгладить внезапный поток.,Сделайте выходной поток более стабильным,Избегается влияние внезапного увеличения потока на систему.
  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. Плавный поток: алгоритм Token Bucket может сглаживать всплески потока.,Сделайте всплески потока равномерно распределенными в течение определенного периода времени.,Избегайте внезапного пикового воздействия потока на систему.
  2. Гибкость: корзиной токенов можно гибко управлять, регулируя скорость генерации токенов и размер корзины.
  3. Разрешить пакетный поток: поскольку ведро токенов может накапливать определенное количество токенов.,Поэтому, когда поток внезапно увеличивается,Если в ведре достаточно токенов,С такими чрезвычайными ситуациями может справиться поток.

недостаток:

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

4 Ограничение распределенного тока

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

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 Создать корзину токенов Redis
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 может стать узким местом производительности всей системы. Чтобы решить эту проблему,Рассмотрите возможность использования кластера Redis для повышения производительности.,Или используйте более производительное оборудование.
  2. Единая точка отказа: если Redis выходит из строя,Это повлияет на всю систему функции ограничения тока. Чтобы решить эту проблему,Вы можете рассмотреть возможность использования Redis в режиме master-slave или дозорном режиме для достижения высокой доступности.
  3. Пропускная способность сети. Redis — это база данных в памяти, основанная на сетевом обмене данными, поэтому пропускная способность сети является ключевым фактором ее производительности. Если пропускная способность сети ограничена, это может привести к снижению скорости передачи запроса, что повлияет на производительность 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 не может обрабатывать большое количество операций применения и выпуска токенов, это может стать узким местом в системе.

5 Резюме

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

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

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

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

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose