задний план
С ростом популярности микрослужб стабильность между службами становится все более и более важной. Мы часто тратим большой опыт на поддержание стабильности служб. Ограничение тока и переход на более раннюю версию автоматических выключателей — два наиболее часто используемых метода. Некоторое время назад у некоторых друзей в группе были некоторые сомнения по поводу использования ограничения тока, кроме того, компания также сделала кое-что, связанное с ограничением тока в недавней акции, поэтому я подытожу и напишу свои взгляды на ограничение тока здесь .
Я просто сказал, что ограничение тока является одним из средств, с помощью которых мы обеспечиваем стабильность услуг, но оно не гарантирует стабильность всех сценариев, Как и его имя, он может играть свою роль только в сценариях с большим трафиком или всплесками трафика. эффект. Например, наша система поддерживает до 100QPS, но вдруг приходит запрос 1000QPS.В это время система может зависнуть напрямую, в результате чего следующий запрос не будет обработан. QPS у него есть, Мы все обрабатываем только запросы 100QPS, а другие запросы напрямую отклоняются.Хотя мы отклонили запросы 900 QPS, наша система не зависла, и наша система может продолжать обрабатывать последующие запросы.Это то, что мы ожидаем. Некоторые студенты могут сказать, что теперь, когда они все в облаке, динамическое масштабирование сервисов должно быть очень простым.Если мы обнаружим, что при особенно большом трафике мы можем автоматически расширить машину для поддержки целевого количества запросов в секунду, поэтому нет необходимости ограничивать ток. На самом деле должно быть довольно много студентов, которые имеют эту идею.Некоторые студенты могут быть одурачены какими-то хвастливыми статьями, поэтому они так думают.Эта идея может быть реализована, когда она особенно идеализируется, но в действительности, есть следующие несколько вопросы:
- Расширение требует времени. Расширение — это просто создание новой машины, а затем повторный выпуск кода.Изучающие Java должны знать, что время для успешного выпуска кода обычно исчисляется не секундами, а минутами.Иногда вы завершаете расширение, скажем, Неопределенный трафик шипы прошли.
- Насколько масштабировать — особенно сложный вопрос. Расширение нескольких машин сложнее.Требуется много расчетов по измерению давления и одно расширение на всю ссылку.Если машины на вашей стороне будут расширены,машины других команд могут остаться узкими местами в итоге,если их не расширять ...это тоже верно один вопрос.
Следовательно, простое расширение не может решить эту проблему, а ограничение тока по-прежнему является навыком, которым мы должны овладеть!
Фундаментальный
Если вы хотите освоить ограничение тока, вам нужно сначала освоить некоторые из его основных алгоритмов.Существует в основном три типа алгоритмов ограничения тока: счетчик, воронка, ведро токенов и другие, разработанные на их основе.
Алгоритм счетчика
Во-первых, давайте поговорим об алгоритме счетчика.Этот алгоритм относительно прост и груб.Нам нужна только одна накопленная переменная, а затем обновлять накопленную переменную каждую секунду, а затем судить, превышает ли накопленная переменная наш максимальный QPS.
int curQps = 0;
long lastTime = System.currentTimeMillis();
int maxQps = 100;
Object lock = new Object();
boolean check(){
synchronized (lock){
long now = System.currentTimeMillis();
if (now - lastTime > 1000){
lastTime = now;
curQps = 0;
}
curQps++;
if (curQps > maxQps){
return false;
}
}
return true;
}
Этот код относительно прост.Мы определяем текущий qps, время последнего обновления накопленной переменной, а также наш максимальный qps и нашу блокировку.Каждый раз, когда мы проверяем, нам нужно судить, нужно ли нам обновлять, если нам нужно обновить Затем вам нужно сбросить и время, и qps, а затем выполнить кумулятивную оценку qps.
Этот алгоритм слишком прост, поэтому проблема очень очевидна.Если наш максимальный qps равен 100, 100 запросов приходят за 0,99 секунды, а затем 100 запросов приходят за 1,01 секунды, это нормально через нашу программу, но мы фактически прошли 200 запросов в течение 0,03 секунды, что точно не соответствует нашим ожиданиям, потому что очень вероятно, что эти 200 запросов напрямую повесят нашу машину.
Счетчик с раздвижным окном
Чтобы решить вышеуказанную критическую проблему, мы можем использовать скользящее окно для решения этой проблемы:Как показано на рисунке выше, мы разделили обычный счетчик 1 с на 5 200 мс.Текущий qps, который мы подсчитали, нужно подсчитать все qps последних 5 окон, а затем вернуться к предыдущему вопросу, 0,99 секунды и 1,01 секунды на самом деле мы находимся в последних 5 окнах, так что здесь не будет критической проблемы со спуртом.
На самом деле, стоимость оборотной стороны, мы обычный счетчик на самом деле количество окон для скользящего счетчика окна 1, чем больше окно, пока мы забиваем, мы используем программный счетчик, когда подсчет будет более точным, но относительно окна обслуживания на Это будет увеличиваться, поэтому мы представим часового, когда он подробно расскажет, как добиться счета скользящего окна.
алгоритм воронки
Решение проблемы критического рывка в счетчике также может быть достигнуто с помощью воронкообразного алгоритма, как показано на следующем рисунке:
В алгоритме воронки нам нужно обратить внимание на дырявое ведро и равномерный отток, каким бы большим ни был поток, он сначала войдет в дырявое ведро, а затем вытечет с равномерной скоростью. Как добиться этой единой скорости в коде? Например, если мы хотим, чтобы равномерная скорость была 100q/s, то мы можем получить, что каждый исходящий поток занимает 10 мс, что аналогично очереди, каждые 10 мс поток берется из головы очереди для освобождения, и наша очередь также является дырявым ведром.Когда поток больше, чем Когда длина очереди, мы можем отклонить лишнюю часть.
У воронкообразного алгоритма есть и определенные недостатки: он не справляется с всплеском трафика (не то же самое, что критический всплеск выше, не путайте). Например, в момент приходит 100 запросов, а в алгоритме дырявого ведра может пройти только один за другим, когда вытекает последний запрос, прошла одна секунда, поэтому алгоритм воронки больше подходит для того, чтобы запросы поступали равномерно, а запросы должны строго контролироваться скоростью сцены.
Алгоритм ведра токенов
Чтобы решить ситуацию с всплеском трафика, мы можем использовать алгоритм корзины маркеров, как показано на следующем рисунке:Нам нужно сосредоточиться на трех этапах на этой карте:
- Производственные токены: что мы тут делаем или если предположить, что максимальный QPS равен 100, то мы конвертируем токен каждые 10 мс каждые 10 мс воронки до максимального токена.
- Потребление токенов: каждый наш трафик будет потреблять корзину токенов. Правила потребления здесь могут быть разными. Это может быть просто потребление одного токена на трафик, или оно может быть основано на разных размерах пакетов трафика или типах трафика. правила потребления, такие как трафик запроса потребляет 1 токен, а трафик записи потребляет 2 токена.
- Судите, пройти ли: если ведра токенов достаточно, то мы пропускаем трафик, если недостаточно, мы можем подождать или отклонить его напрямую.Это можно контролировать с помощью очереди, такой как воронка.
Автономное ограничение тока
Выше мы представили некоторые базовые алгоритмы для ограничения тока.Мы применяем эти алгоритмы к нашим распределенным службам и их можно разделить на два типа: ограничение тока для одной машины и ограничение тока кластера. Ограничение тока одной машины означает, что каждая машина выполняет свое собственное ограничение тока, не влияя друг на друга. Давайте посмотрим, как реализовать ограничение тока одной машины?
guava
Guava — это основная библиотека инструментов Java с открытым исходным кодом, которая включает в себя такие полезные инструменты, как сбор, кеширование и параллелизм. Конечно, она также предоставляет текущие ограничивающие инструменты, которые нам здесь нужны. Основным классом является RateLimiter.
// RateLimiter rateLimiter = RateLimiter.create(100, 500, TimeUnit.MILLISECONDS); 预热的rateLimit
RateLimiter rateLimiter = RateLimiter.create(100); // 简单的rateLimit
boolean limitResult = rateLimiter.tryAcquire();
Метод использования относительно прост.Как показано в приведенном выше коде, нам нужно только построить RateLimiter, а затем вызвать метод tryAcquire.Если возвращается true, это означает, что трафик в это время проходит, в противном случае, трафик ограничен. В гуаве RateLimiter также делится на два типа, один — реализация общего алгоритма корзины токенов, а другой — это RateLimiter с предварительным нагревом, который может постепенно увеличивать скорость выпуска нашей корзины токенов, пока она не достигнет максимума. один также доступен в Sentinel, который можно использовать в некоторых холодных системах, таких как пул соединений с базой данных, который не полностью заполнен и все еще непрерывно инициализируется.
Вот лишь краткое введение в то, как реализовано ведро токенов Guava:
Нормальное ведро токена создаетSmoothBursty
Класс, этот класс также является ключом к нашей реализации ограничения тока, как сделать ограничение тока, находится в нашем tryAcquire:Здесь есть четыре шага:
- Шаг 1: Добавляем блокировку синхронизации.Следует отметить, что в сентинеле блокировки нет.В гуаве она есть, и некоторые проблемы с сентинелом будут решены в будущем.
- Шаг 2: Определяем, можно ли подать заявку на ведро токенов.Если в ведре недостаточно токенов и время ожидания превышает наш таймаут, мы не будем подавать заявку здесь.
- Шаг 3: подайте заявку и получите время ожидания токена, параметры тайм-аута в нашем tryAcquire, это наше максимальное время ожидания, если мы просто позвоним
tryAcquire()
, Не будет ждать второго шага быстрого времени, не удалось. - Шаг 4: Время ожидания сна.
Метод вычета токена указан в методе backupEarliestAvailable:
Хотя кажется, что здесь много процессов, если мы просто вызовемtryAcquire()
, вам нужно только сосредоточиться на двух красных полях:
- Шаг 1: выпуск токенов в соответствии с текущим последним временем. В гуаве нет возможности использовать другие потоки для асинхронного выпуска токенов, и обновление токенов помещается каждый раз, когда мы вызываем текущий метод ограничения. Этот дизайн может стоить изучения Необходимость выполнения асинхронных потоков также может привести к тому, чего мы хотим, и это не так сложно, как асинхронные потоки.
- Шаг 2: Вычтите токен, здесь мы проверили его в canAcquire, токен должен быть успешно вычтен.
Гуава, ограничивающая его, в настоящее время предоставляет два способа ограничения этого, много промежуточного программного обеспечения или бизнес-сервисов, Гуава рассматривается как ограничение собственных инструментов, но Гуава - более ограниченный способ, чтобы изменить динамический текущий предел, и больше стратегий ограничения не поддерживает, поэтому мы собираемся представить часового.
sentinel
Sentinel – это упрощенная структура управления потоком в распределенной сервисной среде Alibaba с открытым исходным кодом. Она уже почти 10 лет выполняет основной сценарий Alibaba Double Eleven. Ее ядром является управление потоком, но оно не ограничивается управлением потоком. мониторинг и т.д.
Текущий лимит с помощью sentinel немного сложнее, чем с гуавой, самый простой код написан ниже:
String KEY = "test";
// ============== 初始化规则 =========
List<FlowRule> rules = new ArrayList<FlowRule>();
FlowRule rule1 = new FlowRule();
rule1.setResource(KEY);
// set limit qps to 20
rule1.setCount(20);
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule1.setLimitApp("default");
rules.add(rule1);
rule1.setControlBehavior(CONTROL_BEHAVIOR_DEFAULT);
FlowRuleManager.loadRules(rules);
// ================ 限流判定 ===========
Entry entry = null;
try {
entry = SphU.entry(KEY);
// do something
} catch (BlockException e1) {
// 限流会抛出BlockException 异常
}finally {
if (entry != null) {
entry.exit();
}
}
- Шаг 1: В Sentinel подчеркивается концепция Ресурса. То, что мы защищаем или делаем, основано на Ресурсе, поэтому сначала нам нужно определить ключ нашего Ресурса. Здесь мы просто устанавливаем его для проверки.
- Шаг 2: Затем мы инициализируем текущее правило ограничения для нашего ресурса. Мы выбираем текущее правило ограничения для QPS и стратегию по умолчанию. По умолчанию здесь используется версия счетчика со скользящим окном, а затем загружается в глобальный диспетчер правил. Внутри, настройка всего правила сильно отличается от настройки гуавы.
- Шаг 3: Второй важной концепцией в Sentinel является Entry. Entry представляет собой операцию с ресурсом, текущая информация о вызове будет сохранена внутри, и запись должна быть закрыта, когда она наконец будет завершена. Когда мы выносим решение о текущем лимите, мы на самом деле получаем Запись,
SphU.entry
То есть ключ для нас, чтобы реализовать наши правила ограничения тока выше.В отличие от гуавы, если ток ограничен, будет выброшено исключение BlockException, и мы обрабатываем текущее ограничение.
Хотя использование Sentinel сложнее, чем GuAVA, алгоритм представляет собой нечто большее, чем ограниченный поток guava.
На основе параллелизма (количество потоков)
То, что мы представили ранее, основано на количестве запросов в секунду. Sentinel предоставляет стратегию, основанную на количестве параллелизма. Эффект аналогичен изоляции семафора. Когда нам нужно предотвратить исчерпание пула бизнес-потоков медленными вызовами, мы можем использовать этот режим.
Вообще говоря, интерфейс http, предоставляемый той же службой, использует пул потоков, такой как используемый нами веб-сервер tomcat, тогда у нас будет пул бизнес-потоков tomcat, если в http есть два метода A и B. Скорость B является относительно быстрым, а скорость A относительно низкой. Если метод A вызывается в большом количестве, поток не может быть освобожден, поскольку скорость A слишком низкая, что может привести к исчерпанию пула потоков. B не получит нить. Мы сталкивались с этим сценарием раньше, что напрямую приводило к отклонению всех запросов, полученных всей службой. Некоторые студенты сказали, что недостаточно ограничить QPS для A. Следует отметить, что QPS в секунду, если время работы нашего интерфейса A больше 1 с, то QPS будет пересчитан после следующей волны приходит А.
Исходя из этого, предоставляется текущий лимит по количеству параллелизма.FLOW_GRADE_THREAD
, этот режим ограничения тока может быть реализован.
На основе QPS.
Ограничение на основе количества запросов в секунду SENTINEL также предлагает четыре стратегии:
-
Политика по умолчанию: установите для параметра «Поведение» значение
CONTROL_BEHAVIOR_DEFAULT
, этот режим является режимом счетчика скользящего окна. Этот метод подходит, когда производительность системы точно известна, например, когда точный уровень воды в системе определяется путем измерения давления. -
Разминка: установите поведение как
CONTROL_BEHAVIOR_WARM_UP
, аналогично разминке, представленной ранее в гуаве. Режим прогрева. Когда система находится на низком уровне воды в течение длительного времени, когда поток внезапно увеличивается, прямое подтягивание системы к высокому уровню воды может мгновенно привести к перегрузке системы. График QPS в этом режиме выглядит следующим образом:
- Равномерная организация очереди: установите для параметра «Поведение» значение
CONTROL_BEHAVIOR_RATE_LIMITER
, Этот режим на самом деле представляет собой воронкообразный алгоритм, преимущества и недостатки которого были объяснены ранее. - WARM UP + Unimplete Queuing: Установите Behavior для Control_Behavior_Warm_up_rate_limiter, before WARM Up to high water level, алгоритм ограничения потока скользящего окна, в этом режиме продолжается алгоритм равномерной очереди.
На основе отношения вызова
Sentinel предоставляет более сложный текущий предел, который может быть более гибким в зависимости от отношения вызова:
- Текущий лимит в соответствии с вызывающим абонентом: использование текущего лимита вызывающего абонента является более сложным и требует вызова
ContextUtil.enter(resourceName, origin)
,origin - это наш идентификатор вызывающего абонента, а затем, когда наше правило устанавливает параметры, установка limitApp может ограничить текущий вызывающий абонент:- Установить как
default
, по умолчанию все вызывающие абоненты имеют ограничение по току. - Установить как
{some_origin_name}
, что означает, что ток ограничен конкретным вызывающим абонентом. - Установить как
other
, который будет ограничивать ток, за исключением вызывающего объекта, представленного параметром referResource конфигурации.
- Установить как
- Ассоциированное управление потоком: он также поддерживается в дозорном. Два связанных ресурса могут влиять на управление потоком друг друга. Например, два интерфейса используют один и тот же ресурс, один интерфейс более важен, а другой интерфейс не так важен, мы можем установить A Правило может ограничивать поток другого неважного интерфейса при доступе к большому количеству важных интерфейсов, предотвращая влияние внезапного потока трафика на этот интерфейс на важный интерфейс.
Некоторые проблемы с часовым
Хотя Sentinel предоставляет так много алгоритмов, у него также есть некоторые проблемы:
- Прежде всего, с помощью sentinel сложно начать работу. По сравнению с двумя строками кода guava, при использовании sentinel необходимо понимать некоторые существительные, а затем использовать их снова. Хотя sentinel предоставляет некоторые аннотации, которые помогают нам упростить использование, лучше гуавы Будь сложным.
- Sentinel требует определенных затрат на эксплуатацию и техническое обслуживание.Использование Sentinel часто требует настройки фона сервера Sentinel.По сравнению с готовым использованием гуавы, существует определенная стоимость эксплуатации и обслуживания.
- В статистике ограничения тока Sentinel есть определенные проблемы с параллелизмом.В исходном коде sentinel нет блокировки.В крайних случаях, если ограничение qps равно 10, если есть 100 логик, которые превышают ток одновременно, все они пройдет в это время А этого не происходит с гуавой.
Эти проблемы в основном сравниваются с текущим лимитом гуавы, ведь у дозорного больше функций и относительно дороже стоит.
Ограничение тока кластера
Все ограничения по току, упомянутые ранее, являются ограничениями по току для одной машины, но мы все находимся в архитектурном режиме микросервисного кластера.Обычно служба будет иметь несколько машин.Например, если есть служба заказов, эта служба имеет 10 машин , то хотим сделать Весь кластер ограничен 500QPS, что делать? Это очень просто. Просто ограничьте ток до 50 для каждой машины. 50 * 10 равно 500. Однако в реальной среде будет дисбаланс нагрузки. Существуют различные алгоритмы балансировки нагрузки при вызове микросервисов, такие как Алгоритмы, такие как приоритет в одном и том же компьютерном зале, обучение ротации, рандомизация и т. д., эти алгоритмы могут привести к тому, что наша нагрузка будет не особенно сбалансирована, что приведет к тому, что QPS всего нашего кластера может быть не 500, а даже быть ограниченным 400. Это мы сталкивались в реальных сценах. Поскольку существует проблема с ограничением тока одной машины, мы должны разработать более полную схему ограничения тока кластера.
redis
Это решение не опирается на текущую ограничительную структуру. Мы можем использовать один и тот же Redis для всего кластера. Нам нужно инкапсулировать текущую ограничивающую логику. Здесь мы используем простейший счетчик для проектирования, и мы используем наше системное время в секундах в качестве key. , установите его в redis (вы можете установить определенное время истечения срока действия для очистки пространства), используйте атомарное дополнение redis, +1 для каждого запроса, а затем оцените, превышает ли текущее значение максимальное значение нашего текущего ограничения.
Решение Redis относительно просто реализовать в целом, но оно сильно зависит от нашего системного времени.Если системное время между разными машинами отклоняется, текущее ограничение может быть неточным.
sentinel
Sentinel предоставляет кластерное решение, которое отличается от некоторых других ограничивающих фреймворков. В Sentinel предусмотрено два режима:
- Независимый режим: Служба ограничения тока развертывается как отдельный сервер, как показано на рисунке ниже, все приложения получают токены с отдельно развернутого сервера токенов.Этот режим подходит для всех ограничений трафика между службами, как показано на рисунке ниже за его получением отправятся и A, и B. Вообще говоря, такой сценарий встречается относительно редко, и чем больше текущий лимит кластера внутри сервиса, тем больше.
- Встроенный режим: во встроенном режиме мы развернем сервер в нашем экземпляре приложения, и мы также можем преобразовать нашу идентификацию сервера-клиента через интерфейс.Конечно, мы можем ввести некоторые настройки логики zk, чтобы позволить нашему лидеру уйти, когда сервер, машина также может автоматически переключаться. Это больше подходит для ограничения тока между одним и тем же сервисным кластером и обладает большей гибкостью, но следует отметить, что большое количество обращений к токен-серверу также может повлиять на наши собственные машины.
Конечно, у Sentinel также есть некоторые восходящие стратегии: если токен-сервер зависнет, мы можем выродиться в наш одномашинный режим ограничения тока, что не повлияет на наши обычные сервисы.
реальный бой
Выше мы представили множество инструментов ограничения тока, но многие студенты все еще не понимают, как ограничить ток. Если мы ограничиваем поток сцены или ресурса, нам необходимо подтвердить следующие пункты:
- Где сделать ограничение тока
- Сколько ограничить
- как выбрать инструмент
Где сделать ограничение тока
Эта проблема сложнее.Многие компании и многие команды имеют разные практики.Когда Meituan запустила волну SOA,в то время я помню,что все сервисы и все интерфейсы нужно ограничивать,и каждую команду просили предоставить интерфейс.Оценить разумный верхний предел QPS. Это теоретически правильно. Мы должны установить верхний предел для каждого интерфейса, чтобы предотвратить перетаскивание всей системы, но стоимость этого очень высока, поэтому большинство компаний или выборочно ограничивают ток.
Прежде всего, нам нужно определить некоторые основные интерфейсы, такие как заказ и оплата в системе электронной коммерции.Если трафик слишком велик, будут проблемы с путем в системе электронной коммерции, такие как граничные интерфейсы, такие как как примирение (не влияет на основной путь), мы не можем установить ограничение тока.
Во-вторых, мы не обязательно ограничиваем поток только на уровне интерфейса, во многих случаях мы ограничиваем поток непосредственно на уровне шлюза, чтобы предотвратить дальнейшее проникновение трафика в ядро системы. Конечно, внешний интерфейс также может ограничивать ток.После того, как внешний интерфейс фиксирует код ошибки текущего ограничения, внешний интерфейс может запрашивать ожидающую информацию, которая на самом деле является частью текущего ограничения. На самом деле, чем больше текущий лимит срабатывает ниже по течению, тем больше потери наших ресурсов, потому что вышестоящий проделал большую работу до лимита нижестоящего.Если текущий лимит сработает в это время, предыдущая работа будет в напрасно.Если это связано с некоторыми откатами Работа также увеличит нашу нагрузку, поэтому для ограничения тока чем выше триггер, тем лучше.
Сколько ограничить
Вопрос на сколько ограничить поток может быть значением исторического опыта большую часть времени.Мы можем мониторить карту через ежедневный qps, а потом добавить в этот контакт немного избыточный QPS.Может это наш текущий лимит. Но есть один сценарий, на который нужно обратить внимание, то есть, когда идет большая акция (здесь имеется в виду сценарий в системе электронной коммерции, другие системы аналогичны сценариям с высокой посещаемостью), трафик нашего система внезапно увеличится, что больше не является нашей повседневной рутиной.QPS, в этом случае нам часто нужно выполнить полное тестирование давления в нашей системе перед большой акцией и найти разумный верхний предел, а затем установить текущий ограничение на основе этого верхнего предела.
как выбрать инструмент
Вообще говоря, у крупных интернет-компаний есть свои инструменты для единого ограничения тока. В других случаях, если нет необходимости в ограничении тока кластера или слиянии, я лично считаю, что выбор RateLimter является относительно хорошим выбором.Он должен быть относительно простым в использовании и практически не требует затрат на обучение.Если есть другие потребности, Я лично считаю, что выбирая Sentinel, Что касается hytrix, я лично не рекомендую его использовать, потому что это больше не поддерживается.
Суммировать
Хотя есть только два слова для ограничения тока, по-настоящему понять ограничение тока и сделать хорошую работу по ограничению тока непросто.Для меня эта статья является лишь поверхностным пониманием, если у вас есть какие-либо лучшие комментарии, которые можно обсудить на моем официальный отчет.
Если вы считаете, что эта статья полезна для вас, то ваше внимание и пересылка - самая большая поддержка для меня, O(∩_∩)O: