Во второй половине этого года Ali представила свою собственную систему ограничения тока Sentinel.В официальном представлении Sentinel использовался ряд высокоуровневых терминов, таких как ограничение тока, переход на более ранние предохранители, формирование трафика, защита системной нагрузки и т. д. , а также красивые прилагательные, такие как легкий, профессиональный, в режиме реального времени и другие. Как потребитель техники, я не могу не вздохнуть громко, увидев такие рекламные слова - NiuB! Более важно то, что пресс-конференцию Sentinel провела старший технический эксперт Али Зиджин, женщина-разработчик, что является редким зрелищем в ИТ-индустрии, где доминируют мужчины.
Я провел целый день, тщательно изучая функции и код Sentinel, и примерно разобрался с общей архитектурой и некоторыми техническими деталями.
Начало работы с Sentinel
Во-первых, Sentinel не особо сложная система, и рядовые технические разработчики без труда разберутся в ее принципах и устройстве. Не смотрите на Sentinel на архитектурной диаграмме, которая окружена серией других промежуточных программ с открытым исходным кодом Это просто великолепный пакет, и его ядро Sentinel Core действительно очень легкое.
Прежде всего, мы начнем с его Hello World, Глубоко понимая этот код входа, мы можем получить представление о его архитектурных принципах.
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.4.0</version>
</dependency>
Существует два типа ограничения тока: одномашинное и распределенное. Ограничение тока на одной машине относится к ограничению количества запросов в секунду, количества одновременных потоков или всего индекса загрузки машины фрагмента кода в текущем процессе. значение, заданное правилом, будет сгенерировано исключение или возвращено значение false. Я называю фрагменты кода с дросселированием здесь «критическими разделами».
Распределенный требует другого централизованного сервера счетов. Этот сервер будет генерировать только определенное количество голосов в секунду для каждого указанного ресурса. Прежде чем выполнять код в критической секции, перейдите к централизованной службе счетов, чтобы собрать билеты. Если сбор прошел успешно Это может быть выполнено, в противном случае будет выдано исключение текущего ограничения. Следовательно, стоимость распределенного ограничения тока высока, и требуется еще одна операция чтения и записи в сети. Если читатели читали мой буклет "Redis Deep Adventures", в нем упоминается текущий модуль ограничения Redis. Текущий принцип ограничения Sentinel похож на него, за исключением того, что сервер счетов Sentinel разработан самостоятельно и использует фреймворк Netty.
Sentinel предоставляет две используемые формы: одна — форма захвата исключений, а другая — логическая форма. То есть, когда срабатывает текущий лимит, выбрасывать ли исключение или возвращать false. Давайте посмотрим на его форму захвата исключений, это автономная версия.
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
public class SentinelTest {
public static void main(String[] args) {
// 配置规则
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("tutorial");
// QPS 不得超出 1
rule.setCount(1);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp("default");
rules.add(rule);
// 加载规则
FlowRuleManager.loadRules(rules);
// 下面开始运行被限流作用域保护的代码
while (true) {
Entry entry = null;
try {
entry = SphU.entry("tutorial");
System.out.println("hello world");
} catch (BlockException e) {
System.out.println("blocked");
} finally {
if (entry != null) {
entry.exit();
}
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {}
}
}
}
Использование Sentinel требует, чтобы мы предоставили правила ограничения тока и на основе правил обернули код критической секции структурой области ограничения тока. В приведенном выше примере количество запросов в секунду для ограниченного учебного ресурса на одной машине не должно превышать 1, но на самом деле его текущее количество запросов в секунду равно 2, дополнительная логика выполнения будет ограничена, и соответствующий метод Sphu.entry() выдаст ограничение. Исключение потока BlockException. Ниже результат его работы
INFO: log base dir is: /Users/qianwp/logs/csp/
INFO: log name use pid is: false
hello world
blocked
hello world
blocked
hello world
blocked
hello world
blocked
...
Из вывода видно, что Sentinel записывает подробные журналы ограничения тока в локальные файлы, которые можно собирать в качестве источника данных для сигналов тревоги.
Давайте взглянем на его логическую форму, которая также очень проста в использовании, с небольшой разницей.
import java.util.ArrayList;
import java.util.List;
import com.alibaba.csp.sentinel.SphO;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
public class SentinelTest {
public static void main(String[] args) {
// 配置规则
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("tutorial");
// QPS 不得超出 1
rule.setCount(1);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp("default");
rules.add(rule);
FlowRuleManager.loadRules(rules);
// 运行被限流作用域保护的代码
while (true) {
if (SphO.entry("tutorial")) {
try {
System.out.println("hello world");
} finally {
SphO.exit();
}
} else {
System.out.println("blocked");
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {}
}
}
}
контроль правил
В приведенном выше примере все правила написаны в коде, в реальных проектах правила должны поддерживать динамическую настройку. Для этого требуется источник конфигурации правил, которым может быть база данных, такая как Redis, Zookeeper и т. д., а также механизм уведомления об изменении правил и фон конфигурации правил, позволяющий менеджерам динамически настраивать правила в фоновом режиме и отправлять их бизнесу. сервер для управления в режиме реального времени.
Некоторые хранилища источников правил не поддерживают механизм уведомления о событиях, например реляционные базы данных.Sentinel также предоставляет правила регулярного обновления, такие как обновление текущих ограничивающих правил в памяти каждые несколько секунд. Ниже приведено определение источника правила Redis.// redis 地址
RedisConnectionConfig redisConf = new RedisConnectionConfig("localhost", 6379, 1000);
// 反序列化算法
Converter<String, List<FlowRule>> converter = r -> JSON.parseArray(r, FlowRule.class);
// 定义规则源,包含全量和增量部分
// 全量是一个字符串key,增量是 pubsub channel key
ReadableDataSource<String, List<FlowRule>> redisDataSource = new RedisDataSource<List<FlowRule>>(redisConf,"app_key", "app_pubsub_key", converter);
FlowRuleManager.register2Property(redisDataSource.getProperty());
Отчетность о состоянии здоровья и проверка
Сервер приложений, обращающийся к Sentinel, должен сообщать о своем текущем состоянии ограничения на Dashboard, чтобы текущее состояние ограничения всех служб могло отображаться в фоновом режиме в режиме реального времени. Sentinel использует модель извлечения для отчета о состоянии. Он регистрирует службу HTTP в текущем процессе. Dashboard будет регулярно обращаться к этой службе HTTP, чтобы получать информацию о состоянии работоспособности и текущих ограничениях каждого процесса службы.
Sentinel должен сообщать адрес службы в Dashboard в виде контрольных пакетов, чтобы Dashboard знал конкретный адрес службы работоспособности HTTP для каждого процесса службы. Если процесс переходит в автономный режим, пакет пульса останавливается, и срок действия соответствующей адресной информации также истечет, так что Dashboard может узнать текущий список допустимых служб процесса в квазиреальном времени.Текущая версия панели мониторинга с открытым исходным кодом не может сохраняться. Когда администратор изменяет правила в фоновом режиме, он будет напрямую контролировать конкретный процесс службы, синхронизируя текущие правила ограничения службы непосредственно через адрес службы работоспособности HTTP. Если приложение будет перезапущено, правила будут автоматически сброшены. Если вы хотите сохранить источник правил через Redis, вам нужно настроить панель инструментов самостоятельно. Его несложно настроить, просто реализуйте встроенный интерфейс сохранения.
Распределенное ограничение тока
Ранее мы упоминали, что для распределенного ограничения тока требуется другой сервер билетов, который распределяет билеты.Только запросы, которые могут получить билеты, могут разрешить выполнение кодов критической секции.Серверы билетов также должны предоставлять источники входных данных для правил.
Тикет-сервер — это единая точка.В случае сбоя Тикет-сервера текущее ограничение сервера приложений автоматически снизится до локального режима.Адаптация кадра
Критическая секция, защищаемая Sentinel, представляет собой блок кода.Расширяя границы критической секции, ее можно напрямую адаптировать к различным фреймворкам, таким как Dubbo, SpringBoot, GRPC и очередям сообщений. Адаптер каждой платформы будет единообразно определять область критической секции на границе запроса, так что пользователю не нужно вручную добавлять код защиты автоматического выключателя, а функция защиты с ограничением тока имплантируется автоматически без какого-либо восприятия.
Слияние понижения
Текущее ограничение — ограничение трафика, то есть количества одновременных QPS или потоков.Другая ситуация — обработка запроса нестабильна или сервис поврежден, из-за чего время обработки запроса слишком велико или исключение всегда выбрасывается часто. В этом случае сервис необходимо понизить. Так называемая обработка понижения версии и обработка ограничения тока не имеют очевидной разницы по форме, и критическая секция определяется в той же форме, разница в том, что нужно подсчитывать выброшенные исключения, чтобы можно было узнать частоту исключений запросов. , С этим индикатором будет срабатывать даунгрейд.
// 定义降级规则
List<DegradeRule> rules = new ArrayList<>();
DegradeRule rule = new DegradeRule();
rule.setResource("tutorial");
// 5s内异常不得超出10
rule.setCount(10);
rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
rule.setLimitApp("default");
rules.add(rule);
DegradeRuleManager.loadRules(rules);
Entry entry = null;
try {
entry = SphU.entry(key);
// 业务代码在这里
} catch (Throwable t) {
// 记录异常
if (!BlockException.isBlockException(t)) {
Tracer.trace(t);
}
} finally {
if (entry != null) {
entry.exit();
}
}
Исключение FlowException выдается при срабатывании текущего ограничения, а исключение DegradeException выдается при срабатывании прерывателя цепи, оба из которых унаследованы от BlockException.
Ограничение тока точки доступа
Существует также специальное правило динамического ограничения тока, используемое для ограничения ресурсов динамических точек доступа. Внутренне алгоритм LRU используется для расчета ресурсов topn hotspot, а затем ресурсы topn ограничены по току, а также предоставляются настройки параметров для специальной обработки особых ресурсов. Например, в следующем примере ограничивается частота доступа одного и того же пользователя, также ограничивается частота доступа одной и той же книги, но для специального пользователя и специальной книги выполняется специальная настройка частоты.
ParamFlowRule ruleUser = new ParamFlowRule();
// 同样的 userId QPS 不得超过 10
ruleUser.setParamIdx(0).setCount(10);
// qianwp用户特殊对待,QPS 上限是 100
ParamFlowItem uitem = new ParamFlowItem("qianwp", 100, String.class);
ruleUser.setParamFlowItemList(Collections.singletonList(uitem));
ParamFlowRule ruleBook = new ParamFlowRule();
// 同样的 bookId QPS 不得超过 20
ruleBook.setParamIdx(1).setCount(20);
// redis 的书特殊对待,QPS 上限是 100
ParamFlowItem bitem = new ParamFlowItem("redis", 100, String.class);
ruleBook.setParamFlowItemList(Collections.singletonList(item));
// 加载规则
List<ParamFlowRule> rules = new ArrayList<>();
rules.add(ruleUser);
rules.add(ruleBook);
ParamFlowRuleManager.loadRules(rules);
// userId的用户访问bookId的书
Entry entry = Sphu.entry(key, EntryType.IN, 1, userId, bookId);
Сложность ограничения тока точки доступа заключается в том, как подсчитать количество обращений к ресурсам точки доступа в скользящем окне фиксированной длины.Sentinel разработал специальную структуру данных под названием LeapArray.В ней есть более сложные конструкции алгоритмов, которые необходимо анализировать отдельно .
Системное адаптивное ограничение тока - защита от перегрузки
Когда нагрузка на систему высока, чтобы предотвратить перегрузку системы флуд-подобными запросами, текущая система должна быть защищена с помощью ограничения тока. Метод защиты заключается в постепенном ограничении количества запросов в секунду.После восстановления нагрузки системы количество запросов в секунду постепенно снижается.Если нагрузка системы снова падает, количество запросов в секунду постепенно снижается. Таким образом достигается динамическое равновесие, в котором задействован специальный алгоритм поддержания баланса. Проблема с индексом нагрузки системы.Он берется из параметра загрузки операционной системы load1.Недостаточно обновление параметра load1 в реальном времени.Длительное время перехода от перегрузки load1 к Блокировка любого запроса в течение определенного времени и освобождение запроса сразу после возобновления загрузки1 неизбежно приведет к сильным колебаниям нагрузки, а обработка службы будет прервана и открыта. По этой причине автор трансплантирует идею алгоритма управления перегрузкой TCP для реализации плавной функции защиты системы от перегрузок. Алгоритм очень тонкий, кодовая реализация не сложная, а эффект очень значительный.
Алгоритм определяет формулу устойчивого состояния, когда установившееся состояние нарушается, нагрузка системы будет колебаться. Суть алгоритма заключается в восстановлении стационарного состояния путем непрерывной регулировки соответствующих параметров при нарушении стационарного состояния.
Формула устойчивого состояния очень проста: ThreadNum * (1/ResponseTime) = QPS.Эта формула хорошо понятна, то есть QPS системы равен количеству потоков, умноженному на количество запросов, которые может выполнить один поток. в секунду. Система выберет и подсчитает количество запросов в секунду и время отклика всех критических секций в режиме реального времени, а затем можно будет рассчитать соответствующее стационарное количество одновременных потоков. Когда нагрузка превышает стандартную, можно определить, нужно ли отклонять текущий запрос, оценивая, превышает ли текущее количество потоков количество потоков в установившемся состоянии.
Для определения правила адаптивного ограничения тока необходимо указать несколько параметров.
- Уровень нагрузки системы, при превышении которого срабатывает функция защиты от перегрузки
- Когда защита от перегрузки превышает стандарт, максимально допустимое количество потоков, максимальное время отклика и максимальное число запросов в секунду не могут быть установлены.
List<SystemRule> rules = new ArrayList<SystemRule>();
SystemRule rule = new SystemRule();
rule.setHighestSystemLoad(3.0);
rule.setAvgRt(10);
rule.setQps(20);
rule.setMaxThread(10);
rules.add(rule);
SystemRuleManager.loadRules(Collections.singletonList(rule));
Также из кода видно, что для системного адаптивного правила ограничения тока не нужно определять имя ресурса, потому что это глобальное правило, которое будет автоматически применяться ко всем критическим секциям. Если нагрузка превысит лимит, все ресурсы критической секции затянут пояса потуже и вместе переживут бурю.