остановился на долгое время《面试补习》, с приходом недавнего школьного набора, он тоже будет поставлен на повестку дня, в процессе разбора八股文В то же время это также может углубить мое понимание, я надеюсь, что это поможет вам в детской обуви ~
Обзор
Статьи в свежем номереПосле коучинга интервью с несколькими детьми я обнаружил некоторые проблемы!В интервью было упомянуто, что в интервью опыт проекта настоящей детской обуви вызвал больше вопросов, и я не знаю, видел ли его кто-нибудь.orz
Эти проблемы в проекте в основном перечислены:
- Чтобы понять, почему вы хотите сделать спайковую систему?
- Для каких сценариев подходит система seckill, а для каких не подходит?
- Подумайте, чего не хватает вашей системе
- Овладейте всеми аспектами вашей системы, включая функциональность, производительность, поток данных и архитектуру развертывания.
- Выбор технологии, почему вы используете Redis, почему используете MQ?
- Технические риски со ссылкой на это промежуточное ПО, преимущества и риски для вашей системы
- Как перейти на аварийное восстановление, как мониторить
Сегодня я написал эту статью о限流Статья также является ключевым техническим моментом в системе seckill, она будет из:技术原理,技术选型,使用场景И так далее, чтобы представить во многих аспектах, пусть в интервью,肆意发挥.
Что такое ограничение тока
Вот пример, который всем известен:三峡大坝排水
- Запас воды в водохранилище «Три ущелья»: понятно, что он является пользователем нашей пиковой активности.
- Отпустите ворота: событие начинается
- Истощение: убивайте успешных пользователей
если нет闸口Теперь, каково влияние? Деревни вниз по течению страдают洪水灾难, и то же самое для вашей системы崩溃!
У вас могут быть сомнения, если бы я этого не сделал蓄水的动作(в Трех ущельях не так много воды), мне это не нужно限流какие? На самом деле это не так.Все мы знаем,сколько исторических проблем с наводнениями решили Три Ущелья.Здесь мы нашлиНаучно-популярная ссылка.
что соответствует нашему秒杀系统Как узнать, когда в нашей системе будет волна用户暴增Шерстяная ткань? Если вы не будете готовы в это время, приведет ли это к потере этой группы пользователей? Более того, система парализована, что также влияет на существующих пользователей.双输
我要这铁棒有何用~
так,限流это наша система定海神针, чтобы наша система оставалась спокойной.
Наконец, пакет данных для иллюстрации限流Собственно сцена:
1个商品
1秒内
100个名额
5000个用户
1000个进入下单页面
4000个超时页面
100个下单
900个库存不足
结果:
100个成功下单
4900个抢单失败
限流量: 1000
мыслительные вопросы
求:我这个服务最大并发量多少?
Как ограничить ток
Просто нарисуйте ссылку для вызова
H5/客户端 -> Nginx -> Tomcat -> 秒杀系统 -> DB
просто резюмировать
- Ограничение тока шлюза
- Регулировка Nginx
- Томкэт дросселирует
- Текущий лимит на стороне сервера
- Автономное ограничение тока
- Распределенное ограничение тока
Ограничение тока шлюза
Регулировка Nginx
Nginx поставляется с двумя модулями ограничения тока:
-
连接数Модуль ограничения токаngx_http_limit_conn_module -
漏桶算法实现的请求Модуль ограничения токаngx_http_limit_req_module
1. ngx_http_limit_conn_module
В основном используется для ограничения скриптовых атак, если начинается пиковая активность,黑客(Притворитесь, в конце концов, наша система должна быть больше и сильнее!) Написание скрипта для атаки приведет к тому, что наша пропускная способность будет потрачена впустую и будет сгенерировано большое количество недействительных запросов.Для таких запросов мы можем ограничить количество ip связи.
Мы можем реализовать ограничения, добавив следующую конфигурацию в http{} в nginx_conf:
#限制每个用户的并发连接数,取名one
limit_conn_zone $binary_remote_addr zone=one:10m;
#配置异常日志,和状态码
limit_conn_log_level error;
limit_conn_status 503;
# 在server{} 限制用户并发连接数为1
limit_conn one 1;
2. ngx_http_limit_req_module
Выше указано количество ip-соединений, так что, если мы хотим контролировать количество запросов? Метод регулирования заключается в использовании алгоритма воронки, фиксировании количества запросов, обрабатываемых в секунду, и откладывании слишком большого количества запросов. Если частота запросов превышает значение, настроенное в поле лимита, обработка запросов будет задержана или прервана, поэтому все запросы обрабатываются с заданной частотой.
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
#设置每个IP桶的数量为5
limit_req zone=one burst=5;
3. Как понять количество подключений и количество запросов
- Лимит соединений (ngx_http_limit_conn_module) Для каждого IP мы получим только один, и только когда этот IP будет обработан, я получу следующий. (В единицу времени обрабатывается только одно соединение)
Вкусная интерпретация: в лимите туалета (IP) есть только одна яма, и только когда я закончу, следующий человек может использовать ее.
- Ограничение количества запросов (ngx_http_limit_req_module)
пройти через
漏桶算法, отпустите запрос в соответствии с единицей времени, независимо от того, может ваш сервер его обработать или нет, я его отпущу, эй, просто отпустите!
Изысканная интерпретация: В туалете пять ям, я помещаю 5 человек в одну минуту и 5 человек в следующую минуту. В нем может быть 5 человек, может быть 10 человек, я не знаю.
4. Как выбрать?
Возможно, интервьюер спросит вас, какую текущую стратегию ограничения использовать и при каких обстоятельствах, услышав, что вы так много знаете о текущем ограничении nginx.
- Регулирование IP: может быть настроено до начала события, а также может использоваться для предотвращения атак по сценарию (в случае IP-прокси)
- Регулирование запросов: можно настроить расписание для защиты наших серверов от сбоев, вызванных всплесками трафика.
алгоритм дырявого ведра
Основные концепции алгоритма дырявого ведра следующие:
- Негерметичное ведро фиксированной емкости, из которого вытекают капли воды с постоянной постоянной скоростью;
- Если ведро пустое, капли воды не должны течь;
- Вода может течь в дырявое ведро с любой скоростью;
- Если входящая капля превышает вместимость ведра, входящая капля переполняется (отбрасывается), в то время как вместимость негерметичного ведра не изменяется.
Томкэт дросселирует
Это не очень полезно, но давайте познакомимся~
Может нынешняя детская обувь, даTomcatЯ мало что знаю, в конце концовSpringBootупакованный внутриTomcat, делая разработчиков все более и более ленивыми, но основной причиной эволюции человека является лень, так что это неплохо.
В конфигурационном файле Tomcat естьmaxThreads
<Connector port="8080" connectionTimeout="30000" protocol="HTTP/1.1"
maxThreads="1000" redirectPort="8000" />
Это, кажется, нечего вводить.Если вы столкнулись со своим стресс-тестом, и параллелизм не может подняться, вы можете проверить эту конфигурацию.
Во время интервью интервьюер спросил меняTomcatЭта проблема:
Tomcat 默认最大连接数是多少?
你们服务器的线程数设置了多少?
线程占用内存是多少?
Суммировать
объединить наши秒杀系统, то при введении нашей системы мы можем сказать, что в текущем лимите, с точки зрения шлюза, мы можем использоватьNginxизngx_http_limit_conn_moduleМодуль допускает только один запрос IP в единицу времени, что позволяет избежать множественных запросов от пользователей и снизить нагрузку на службу. После входа в интерфейс заказа в единицу времени будет сгенерировано несколько запросов, которые можно использоватьngx_http_limit_req_moduleмодуль для ограничения количества запросов, чтобы избежатьIPограничений, что приводит к потере заказов.
Кроме того, перед запуском сервиса мы проводим максимальный одновременный стресс-тест на сервере (например,200并发), Таким образом, вTomcatмаксимально разрешенных запросов, установлено значение (300, слегка приподнят, есть и другие запросы).
Регулировка сервера
Автономное ограничение тока
Если развертывание нашей системы представляет собой только одну машину, то мы можем напрямую использовать решение для ограничения тока на одной машине (в конце концов, вам нужно использовать распределенное ограничение тока для одной машины, не слишком ли это~)
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1.1-jre</version>
</dependency>
пример кода
public static void main(String[] args) throws InterruptedException {
// 每秒产生 1 个令牌
RateLimiter rt = RateLimiter.create(1, 1, TimeUnit.SECONDS);
System.out.println("try acquire token: " + rt.tryAcquire(1) + " time:" + System.currentTimeMillis());
System.out.println("try acquire token: " + rt.tryAcquire(1) + " time:" + System.currentTimeMillis());
Thread.sleep(2000);
System.out.println("try acquire token: " + rt.tryAcquire(1) + " time:" + System.currentTimeMillis());
System.out.println("try acquire token: " + rt.tryAcquire(1) + " time:" + System.currentTimeMillis());
System.out.println("-------------分隔符-----------------");
}
RateLimiter.tryAcquire()а такжеRateLimiter.acquire()Оба метода получают токен через текущий ограничитель,
1. попробоватьПриобрести
Поддерживайте входящее время ожидания, оценивайте время токена самой ранней генерации с помощью canAcquire и решайте, стоит ли ждать получения следующего токена.
public boolean tryAcquire(int permits, long timeout, TimeUnit unit);
private boolean canAcquire(long nowMicros, long timeoutMicros) {
return queryEarliestAvailable(nowMicros) - timeoutMicros <= nowMicros;
}
Образец кода:
public static void main(String[] args) throws InterruptedException {
// 每秒产生 1 个令牌
RateLimiter rt = RateLimiter.create(1, 3, TimeUnit.SECONDS);
System.out.println("try acquire token: " + rt.tryAcquire(1,TimeUnit.SECONDS) + " time:" + System.currentTimeMillis());
System.out.println("try acquire token: " + rt.tryAcquire(5,TimeUnit.SECONDS) + " time:" + System.currentTimeMillis());
Thread.sleep(10000);
System.out.println("-------------分隔符-----------------");
System.out.println("try acquire token: " + rt.tryAcquire(1,TimeUnit.SECONDS) + " time:" + System.currentTimeMillis());
System.out.println("try acquire token: " + rt.tryAcquire(1,TimeUnit.SECONDS) + " time:" + System.currentTimeMillis());
}
Выходной результат:
2. приобрести
Acquire блокируется и ожидает получения токена. Глядя на исходный код, вы можете увидеть операцию синхронной блокировки:
Образец кода:
RateLimiter rt = RateLimiter.create(1);
// 每秒产生 1 个令牌
for (int i = 0; i < 11; i++) {
new Thread(() -> {
// 获取 1 个令牌
rt.acquire();
System.out.println("try acquire token success,time:" +System.currentTimeMillis() + " ThreaName:"+Thread.currentThread().getName());
}).start();
}
Выходной результат:
алгоритм токена
Несколько концепций были упомянуты выше, вnignxмы упоминали, что漏斗算法 ,существуетRateLimiterЗдесь мы упомянем, что令牌算法
Мы можем объяснить это с помощью приведенной выше диаграммы, есть ведро с ограниченной емкостью, и токены добавляются в это ведро с фиксированной скоростью. Так как вместимость корзины ограничена, добавлять в нее токены бесконечно нельзя, если в момент достижения токеном корзина будет заполнена, токен будет сброшен. Для каждого запроса из корзины удаляется n токенов, если количество токенов в корзине меньше n, то запрос будет отклонен или заблокирован.
Вот несколько ключевых свойств
/** The currently stored permits. */
double storedPermits; //目前令牌数量
/** The maximum number of stored permits. */
double maxPermits; //最大令牌数量
private long nextFreeTicketMicros = 0L; //下一个令牌获取时间
Перед приобретением токена будет применяться правило суждения, чтобы определить, соответствует ли текущее время получения токена последнему времени получения токена — времени производства токена,
Например : В этот раз я получаю токен за 100 секунд, а время генерации токена 10 секунд.Поэтому когда я прихожу за его получением через 105 секунд, независимо от того, есть ли токен в ведре токенов, я не могу получить токен .
private boolean canAcquire(long nowMicros, long timeoutMicros) {
return queryEarliestAvailable(nowMicros) - timeoutMicros <= nowMicros;
}
Вот в чем дело!!!
Итак, какая польза от количества токенов (акций) в ведре токенов? Для разных запросов мы можем установить разное количество токенов, для высокого приоритета требуется только один токен, для низкого приоритета требуется несколько токенов. Затем, когда время для получения токена истекло, выносится решение следующего уровня, чтобы определить, достаточно ли количества токенов.Запросы с высоким приоритетом (те, которые требуют относительно небольшого количества токенов) могут быть выпущены немедленно! ! ! ! !
существуетRateLimitАлгоритм обновления токена в:
void resync(long nowMicros) {
// if nextFreeTicket is in the past, resync to now
if (nowMicros > nextFreeTicketMicros) {
double newPermits = (nowMicros - nextFreeTicketMicros) / coolDownIntervalMicros();
storedPermits = min(maxPermits, storedPermits + newPermits);
nextFreeTicketMicros = nowMicros;
}
}
Ограничение тока кластера
с нами秒杀系统Чтобы стать больше и сильнее, машина определенно не сможет удовлетворить наши требования, тогда наша архитектура развертывания будет преобразована в следующую архитектурную диаграмму (简版)
Прежде чем ограничить текущий поток кластера, задайте вопрос:
Разве мы не можем использовать решение для развертывания на одном компьютере для развертывания кластера?
Ответ определенно да, мы можем单机限流Решение распространяется на каждую машину в кластере, затем каждый день на машине повторно используется один и тот же набор ограничивающего ток кода (RateLimitвыполнить).
Так что же не так с этим планом?
- Неравномерное распределение трафика
- предел ошибки
- Обновление не своевременное
В основном говорят о误限, все запросы, полученные нашим сервером, имеютnginxраспределять, если определенный период времени, из-за неравномерного распределения запросов(60,30,10比例分配,限流50qps), запустит регулирование первой машины, а для кластера мое общее регулирование阀值за150 qps,Сейчас100qpsЭто ограничено, так что это точно не сработает!
Реализация Redis
Справочная документация:nuggets.capable/post/684490…
мы можем использоватьRedisупорядоченный наборZSetДля реализации ограничения тока алгоритма временного окна процесс реализации заключается в использованииZSetизkeyхранение ограниченоID,scoreИспользуется для хранения времени запроса.После прихода каждого запроса сначала очистить объем доступа предыдущего временного окна, и сравнить номер текущего временного окна с максимально допустимым объемом доступа.Если он больше или равен к максимальному объему доступа, возвратfalseВыполнять операции ограничения тока, отвечающие за выполнение бизнес-логики, иZSetДобавьте действительную запись доступа в .
У этой реализации есть два недостатка:
- Используйте ZSet для хранения каждой записи доступа, если объем данных относительно велик, он займет много места, например, когда 60s разрешает доступ 100W;
- Выполнение этого кода является неатомарной операцией, которая сначала оценивается, а затем добавляется, а выполнение другой бизнес-логики может быть вкраплено в промежутки посередине, что в конечном итоге приведет к неточным результатам.
Текущее ограничивающее промежуточное ПО
SentinelЭто легкий и высокодоступный компонент управления потоком для распределенной сервисной архитектуры, разработанный командой промежуточного программного обеспечения Alibaba.流量控制,熔断降级,系统负载保护и другие параметры, чтобы помочь пользователям защитить стабильность услуг.
Принцип миддлвара, ограничивающего ток, состоит в том, что вещей слишком много, здесь я кратко разделил некоторые различия между ними, напишу отдельную статью, чтобы поделиться ею позже.SentinelПринцип реализации! В настоящее время относительно легко понять, что нижний слой основан на滑动窗口способ достижения
Алгоритм скользящего окна
существуетSentinelа такжеHystrixБазовая реализация滑动窗口, вот краткое описание того, что такое скользящее окно, в1SВнутри я разрешаю 5 запросов через0~200ms,200~400msИ так далее, когда придет время1.2s, наш временной интервал становится 200 мс ~ 1200 мс. Тогда первый запрос не попадает в статистический диапазон. Текущее общее количество запросов равно4, так что новый запрос может быть принят в обработку!
Суммировать
Просто хочу посплетничать, на картинке я нарисовал, я перечислилHystrix(дикобраз),Sentinel(сторожевой) и муравьиный эндогенныйGuardian(сторожить). Всех их объединяет одно:保护. У дикобразов крепкие шипы для защиты их мягких тел, а часовые и охранники защищают свои семьи позади них.
Когда интервьюер спрашивает вас, почему вы используете дросселирование, ваша первая реакция должна быть такой:保护系统, защитите систему от вреда! Это основная причина, по которой вы должны использовать различные стратегии дросселирования.
При обсуждении высокой доступности мы будем думать,削峰,限流а также熔断. Их цели — защитить нашу систему и повысить доступность системы, которую мы часто называем доступностью системы.几个9, Эти данные защищены различными стратегиями обеспечения высокой доступности.
Дальнейшие планы:
-
熔断, в сочетании сSentinelПозвольте мне представить принцип системы seckill с использованием автоматического выключателя. -
削峰, в сочетании сRocketMQРассказать о преимуществах и недостатках ограничения пиков, представитьMQрасходы и риски
Обратите внимание, не потеряйтесь
Ладно, это все, что касается этой статьи. Каждую неделю я буду обновлять несколько высококачественных интервью с крупными фабриками и статьи, связанные с общими технологическими стеками. Спасибо за возможность видеть это, если эта статья хорошо написана, пожалуйста, попросите три подряд! ! ! Творить не просто, спасибо за поддержку и признание, увидимся в следующей статье!
я九灵, есть детская обувь, которую нужно сообщить, вы можете добавить меня wx,Jayce-K, обратите внимание на общедоступный номер:Java 补习课, осваивайте информацию из первых рук!
Если в этом блоге есть какие-либо ошибки, пожалуйста, критикуйте и советуйте, это очень ценится!