1. Введение
В предыдущей статье я проанализировал, как Sentinel считает метрики данных. В этой статье в основном анализируются функции и реализации некоторых функциональных слотов на вызывающем канале, включая четыре функции: адаптация системы, управление черным и белым списками, управление потоком и понижение версии предохранителя.
2. Правила игровых слотов Sentinel
2.1. Определение правил
Прежде чем анализировать различные функциональные слоты, давайте взглянем на определение правил Sentinel.
Sentinel использует Rule для представления правил. Rule — это интерфейс. Rule имеет только один метод, passCheck(), который указывает, передано ли правило.
AbstractRule реализует Rule — абстрактный класс, определяющий ресурсы и ограниченные приложения, которым принадлежит это правило. Все конкретные правила наследуются от этого правила.
2.2 Загрузка или обновление правил
После того, как определенные правила определены, правила должны быть загружены в систему. За этот процесс загрузки отвечает диспетчер правил. Например, если определено системное адаптивное правило SystemRule, соответствующий диспетчер правил SystemRuleManager загрузит правило. Возьмем в качестве примера SystemRuleManager для анализа загрузки правил.
Каждый менеджер правил будет иметь обработчик изменения правила, который наследует SimplePropertyListener как переменную.Когда правило изменяется, он выполняет соответствующую обработку обновления. Каждый менеджер правил определяет внутренний класс как конкретную реализацию этой переменной, например SystemRuleManager:
//创建一个文件处理器
private final static SystemPropertyListener listener = new SystemPropertyListener();
//定义一个处理该规则的处理器类
static class SystemPropertyListener extends SimplePropertyListener<List<SystemRule>>{
。。。
}
Как видите, SystemRuleManager создает SystemPropertyListener как обработчик изменений файла, а SystemPropertyListener является внутренним классом внутри него.
SentinelProperty также определяется в диспетчере правил.SentinelProperty представляет информацию о конфигурации в Sentinel, и это место является правилом, представляющим конфигурацию. Затем к правилу будет добавлен определенный обработчик правил, и при изменении правила для обработки будет использоваться соответствующий обработчик правил.
private static SentinelProperty<List<SystemRule>> currentProperty = new DynamicSentinelProperty<List<SystemRule>>();
currentProperty.addListener(listener);
В качестве примера возьмем обновление SystemRule, когда правила определены, вызов loadRules() из SystemRuleManager обновит правила.
public static void loadRules(List<SystemRule> rules) {
currentProperty.updateValue(rules);
}
При вызове loadRules() фактически вызывается метод updateValues() объекта DynamicSentinelProperty:
public boolean updateValue(T newValue) {
if (isEqual(value, newValue)) {
return false;
}
RecordLog.info("[DynamicSentinelProperty] Config will be updated to: " + newValue);
value = newValue;
for (PropertyListener<T> listener : listeners) {
listener.configUpdate(newValue);
}
return true;
}
Можно видеть, что метод updateValues() DynamicSentinelProperty на самом деле вызывает метод configUpdate() процессора изменения правил, поэтому способ обновления определяется внутренним классом SimplePropertyListener, определенным в каждом диспетчере правил.
Выше показан процесс загрузки правил.Общий процесс загрузки различных правил одинаков, но конкретная логика загрузки обновляется с помощью SimplePropertyListener, определенного в собственном диспетчере правил.
3. Система адаптивного ограничения тока
3.1 Что такое система адаптивного ограничения тока
Правила защиты системы контролируются входящим трафиком на уровне приложений, а индикаторы приложений отслеживаются по нескольким измерениям, таким как загрузка отдельной машины, использование ЦП, среднее время восстановления, входящее количество запросов в секунду и количество одновременных потоков, так что система может работать с максимально возможной пропускной способностью, обеспечивая при этом общую стабильность системы.
Правила защиты системы применяют общее измерение, а не измерение ресурсов, и действуют только на входящий трафик. Входящий трафик относится к входящему в приложение трафику (EntryType.IN), например запросам, полученным веб-службами или серверами Dubbo, которые все являются входящим трафиком.
Системные правила поддерживают следующие режимы:
-
Адаптация нагрузки (действительно только для Linux/Unix-подобных машин): Загрузка системы1 используется в качестве эвристического индикатора для адаптивной защиты системы. Когда загрузка системы1 превышает установленное эвристическое значение, а текущее количество одновременных потоков в системе превышает расчетную емкость системы, срабатывает защита системы (этап BBR). Емкость системы оценивается по формуле maxQps * minRt системы. Эталонное значение параметра обычно равно ядрам ЦП * 2,5.
-
Загрузка ЦП (версия 1.5.0+): защита системы срабатывает, когда загрузка ЦП системы превышает пороговое значение (диапазон значений 0,0-1,0), более чувствителен.
-
Средняя RT: защита системы срабатывает, когда средняя RT всего входящего трафика на одном компьютере достигает порогового значения в миллисекундах. Количество одновременных потоков: когда количество одновременных потоков всего входящего трафика на одном компьютере достигает порогового значения, срабатывает защита системы.
-
Ingress QPS: Когда количество запросов в секунду всего входящего трафика на одном компьютере достигает порогового значения, срабатывает защита системы.
Приведенный выше текст взят из официального документа Sentinel.
2.2. SystemRule
SystemRule представляет собой определение правила адаптивной защиты системы и определяет параметры нагрузки, процессора, количества запросов в секунду, скорости передачи и потоков.
public class SystemRule extends AbstractRule {
/**
* negative value means no threshold checking.
*/
private double highestSystemLoad = -1;
/**
* cpu usage, between [0, 1]
*/
private double highestCpuUsage = -1;
private double qps = -1;
private long avgRt = -1;
private long maxThread = -1;
}
2.3. SystemRuleManager
SystemRuleManager — это базовый класс, реализующий адаптивную защиту системы.Он отвечает за управление адаптивными правилами системы, включая загрузку и обновление правил, а также проверку того, удовлетворяет ли текущий входной вызов правилам.
public class SystemRuleManager {
private static volatile double highestSystemLoad = Double.MAX_VALUE;
private static volatile double highestCpuUsage = Double.MAX_VALUE;
private static volatile double qps = Double.MAX_VALUE;
private static volatile long maxRt = Long.MAX_VALUE;
private static volatile long maxThread = Long.MAX_VALUE;
private static volatile boolean highestSystemLoadIsSet = false;
private static volatile boolean highestCpuUsageIsSet = false;
private static volatile boolean qpsIsSet = false;
private static volatile boolean maxRtIsSet = false;
private static volatile boolean maxThreadIsSet = false;
/**
* 是否存在指定的系统规则,即是否调用SystemRuleManager.loadRules()加载规则
*/
private static AtomicBoolean checkSystemStatus = new AtomicBoolean(false);
/**
* 一个获取系统当前的load和cpu使用的任务
*/
private static SystemStatusListener statusListener = null;
/**
* 系统规则改变后的处理器,主要将规则设置为指定的规则
*/
private final static SystemPropertyListener listener = new SystemPropertyListener();
/**
* 系统规则改变后的处理器,主要将规则设置为指定的规则
*/
private static SentinelProperty<List<SystemRule>> currentProperty = new DynamicSentinelProperty<List<SystemRule>>();
/**
*
*/
private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1,
new NamedThreadFactory("sentinel-system-status-record-task", true));
static {
checkSystemStatus.set(false);
statusListener = new SystemStatusListener();
//定时任务5秒后开始,每秒执行一次
scheduler.scheduleAtFixedRate(statusListener, 5, 1, TimeUnit.SECONDS);
currentProperty.addListener(listener);
}
...
}
Основные значения вышеуказанных параметров:
- Десять параметров, определенных выше, в основном предназначены для описания параметров адаптивной защиты системы.
- checkSystemStatus: требуется ли адаптивная защита системы.
- statusListener: задача, отвечающая за получение рабочих параметров системы.
- listener: обработчик после изменения системных правил.
- currentProperty: текущий файл конфигурации.
- планировщик: запланированная задача, отвечающая за запуск statusListener.
Глядя на блок статического кода, он в основном предназначен для инициализации планировщика, установки выполняемой задачи и частоты и добавления процессора системных правил в currentProperty.
SystemRuleManager будет отвечать за загрузку правил, эта часть была упомянута во втором разделе.
В SystemRuleManager также есть один из самых важных методов, checkSystem(), который отвечает за проверку того, соответствуют ли входящие запросы правилам, адаптивно установленным системой.
public static void checkSystem(ResourceWrapper resourceWrapper) throws BlockException {
// Ensure the checking switch is on.
//如果没有加入系统规则,则不需要检查
if (!checkSystemStatus.get()) {
return;
}
// for inbound traffic only
//如果不是系统入口的资源,不检查
if (resourceWrapper.getType() != EntryType.IN) {
return;
}
//根据全局的ClusterNode获取数据指标,ClusterNode是一个类变量,全局唯一,类加载后生成。
// 每次通过check后再StatisticSlot中累加统计
// total qps
double currentQps = Constants.ENTRY_NODE == null ? 0.0 : Constants.ENTRY_NODE.successQps();
if (currentQps > qps) {
throw new SystemBlockException(resourceWrapper.getName(), "qps");
}
// total thread
int currentThread = Constants.ENTRY_NODE == null ? 0 : Constants.ENTRY_NODE.curThreadNum();
if (currentThread > maxThread) {
throw new SystemBlockException(resourceWrapper.getName(), "thread");
}
double rt = Constants.ENTRY_NODE == null ? 0 : Constants.ENTRY_NODE.avgRt();
if (rt > maxRt) {
throw new SystemBlockException(resourceWrapper.getName(), "rt");
}
// load. BBR algorithm.
//如果当前机器的load大于设置的值
if (highestSystemLoadIsSet && getCurrentSystemAvgLoad() > highestSystemLoad) {
if (!checkBbr(currentThread)) {
throw new SystemBlockException(resourceWrapper.getName(), "load");
}
}
// cpu usage
if (highestCpuUsageIsSet && getCurrentCpuUsage() > highestCpuUsage) {
if (!checkBbr(currentThread)) {
throw new SystemBlockException(resourceWrapper.getName(), "cpu");
}
}
}
Конкретная логика в checkSystem() описана выше, конкретный принцип реализации можно найти в официальной документации.
2.4. SystemSlot
SystemSlot — функциональный слот, отвечающий за адаптивную защиту системы, при поступлении каждой внутренней записи будет выполняться проверка адаптивной защиты системы. SystemSlot очень прост, он в основном вызывает метод SystemRuleManager.checkSystem() в методе entry() для проверки адаптивной защиты системы, конкретная логика все еще находится в SystemRuleManager.
3. AuthoritySlot
Черный и белый список ограничивает передачу ресурса по источнику запроса ресурса (происхождению).Если настроен белый список, может пройти только источник запроса в белом списке, если настроен черный список, запрос источник в черный список не пройдет, а остальные запросы пройдут. .
3.1. AuthorityRule
AuthorityRule представляет собой набор правил для черного и белого списка, который в основном включает настройки атрибутов, одно из которых является ограниченным именем источника, а несколько источников разделены запятыми. Также необходимо установить белый или черный список при установленном ограничении.
private String limitApp;
private int strategy = RuleConstant.AUTHORITY_WHITE;
3.2. AuthorityRuleManager
AuthorityRuleManager аналогичен SystemRuleManager из предыдущего раздела и отвечает за управление загрузкой черных и белых списков. Давайте посмотрим на определения атрибутов:
public final class AuthorityRuleManager {
/**
* 保存权限配置,以resource为key,所以同一个resource只能有一个最新的权限规则
*/
private static Map<String, Set<AuthorityRule>> authorityRules = new ConcurrentHashMap<>();
/**
* 规则改变处理器
*/
private static final RulePropertyListener LISTENER = new RulePropertyListener();
/**
* 当前规则
*/
private static SentinelProperty<List<AuthorityRule>> currentProperty = new DynamicSentinelProperty<>();
static {
currentProperty.addListener(LISTENER);
}
}
Как и в SystemRuleManager, в AuthorityRuleManager также есть обработчик изменения правила RulePropertyListener. Этот RulePropertyListener является внутренним классом для AuthorityRuleManager, а затем также имеет класс конфигурации currentProperty, который представляет текущую конфигурацию. Когда необходимо загрузить правила обновления, логика аналогична что из SystemRuleManager, так что больше не описывать.
3.3. AuthoritySlot
AuthoritySlot — это слот функции, отвечающий за обработку черного и белого списка.Когда запись поступает, вызовите checkBlackWhiteAuthority() для проверки.
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args)
throws Throwable {
checkBlackWhiteAuthority(resourceWrapper, context);
fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
/**
* 检查黑白名单
* @param resource
* @param context
* @throws AuthorityException
*/
void checkBlackWhiteAuthority(ResourceWrapper resource, Context context) throws AuthorityException {
//获取所有的规则
Map<String, Set<AuthorityRule>> authorityRules = AuthorityRuleManager.getAuthorityRules();
if (authorityRules == null) {
return;
}
//获取指定resource的规则
Set<AuthorityRule> rules = authorityRules.get(resource.getName());
if (rules == null) {
return;
}
for (AuthorityRule rule : rules) {
if (!AuthorityRuleChecker.passCheck(rule, context)) {
throw new AuthorityException(context.getOrigin(), rule);
}
}
}
Видно, что это место в основном получает все правила черного и белого списков, а затем проходит и вызывает AuthorityRuleChecker.passCheck() для проверки Конкретная логика проверки очень проста и не будет здесь описываться.
4. Управление потоком
Принцип управления потоком заключается в отслеживании таких показателей, как количество запросов в секунду или количество одновременных потоков трафика приложения, и управлении трафиком при достижении заданного порога, чтобы избежать перегрузки мгновенным пиком трафика, тем самым обеспечивая высокую доступность заявление.
4.1. FlowRule
FlowRule означает правило управления потоком, которое определяет различные параметры управления потоком.
public class FlowRule extends AbstractRule {
/**
* The threshold type of flow control (0: thread count, 1: QPS).
*/
private int grade = RuleConstant.FLOW_GRADE_QPS;
/**
* Flow control threshold count.
*/
private double count;
/**
* Flow control strategy based on invocation chain.
*
* {@link RuleConstant#STRATEGY_DIRECT} for direct flow control (by origin);
* {@link RuleConstant#STRATEGY_RELATE} for relevant flow control (with relevant resource);
* {@link RuleConstant#STRATEGY_CHAIN} for chain flow control (by entrance resource).
*/
private int strategy = RuleConstant.STRATEGY_DIRECT;
/**
* Reference resource in flow control with relevant resource or context.
*/
private String refResource;
/**
* Rate limiter control behavior.
* 0. default(reject directly), 1. warm up, 2. rate limiter, 3. warm up + rate limiter
*/
private int controlBehavior = RuleConstant.CONTROL_BEHAVIOR_DEFAULT;
private int warmUpPeriodSec = 10;
/**
* Max queueing time in rate limiter behavior.
*/
private int maxQueueingTimeMs = 500;
private boolean clusterMode;
/**
* Flow rule config for cluster mode.
*/
private ClusterFlowConfig clusterConfig;
/**
* The traffic shaping (throttling) controller.
*/
private TrafficShapingController controller;
Правило ограничения тока в основном состоит из следующих факторов, и мы можем комбинировать эти элементы для достижения различных эффектов ограничения тока:
- ресурс: имя ресурса, то есть объект текущего ограничивающего правила
- count: текущий предельный порог
- класс: пороговый тип текущего ограничения (количество запросов в секунду или количество одновременных потоков).
- limitApp: источник вызова для управления потоком, если он установлен по умолчанию, источник вызова не будет различим.
- стратегия: Вызвать текущую стратегию ограничения отношений
- controlBehavior: эффект управления потоком (прямой отказ, разминка, равномерная очередь)
4.2. FlowSlot
FlowSlot — функциональный слот, отвечающий за управление потоком данных, конкретная реализация которого выглядит следующим образом:
* 流量规则检查器
*/
private final FlowRuleChecker checker;
public FlowSlot() {
this(new FlowRuleChecker());
}
...
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
boolean prioritized, Object... args) throws Throwable {
checkFlow(resourceWrapper, context, node, count, prioritized);
fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
void checkFlow(ResourceWrapper resource, Context context, DefaultNode node, int count, boolean prioritized)
throws BlockException {
checker.checkFlow(ruleProvider, resource, context, node, count, prioritized);
}
/**
* 规则提供者
*/
private final Function<String, Collection<FlowRule>> ruleProvider = new Function<String, Collection<FlowRule>>() {
@Override
public Collection<FlowRule> apply(String resource) {
// Flow rule map should not be null.
Map<String, List<FlowRule>> flowRules = FlowRuleManager.getFlowRuleMap();
return flowRules.get(resource);
}
};
...
FlowRuleChecker определен в FlowSLot, и FlowRuleChecker отвечает за проверку текущих ограничивающих правил. Можно видеть, что фактическая логика ограничения потока FlowSlot реализуется путем вызова FlowRuleChecker. При вызове метода checkFlow() FlowRuleChecker вам необходимо передать ruleProvider, который является функцией.
4.3. FlowRuleChecker
Как упоминалось выше, за проверку управления потоком отвечает FlowRuleChecker, в FlowSlot вызывается метод checkFlow() FlowRuleChecker:
public void checkFlow(Function<String, Collection<FlowRule>> ruleProvider, ResourceWrapper resource,
Context context, DefaultNode node, int count, boolean prioritized) throws BlockException {
if (ruleProvider == null || resource == null) {
return;
}
Collection<FlowRule> rules = ruleProvider.apply(resource.getName());
if (rules != null) {
for (FlowRule rule : rules) {
if (!canPassCheck(rule, context, node, count, prioritized)) {
throw new FlowException(rule.getLimitApp(), rule);
}
}
}
}
checkFlow() очень прост, то есть, чтобы получить текущие ограничивающие правила, пройти и вызвать метод canPassCheck() для проверки и выдать исключение FlowException, если проверка не удалась.
public boolean canPassCheck(/*@NonNull*/ FlowRule rule, Context context, DefaultNode node, int acquireCount,
boolean prioritized) {
String limitApp = rule.getLimitApp();
if (limitApp == null) {
return true;
}
if (rule.isClusterMode()) {
return passClusterCheck(rule, context, node, acquireCount, prioritized);
}
return passLocalCheck(rule, context, node, acquireCount, prioritized);
}
canPassCheck() также очень прост, то есть вызывает разные методы в соответствии с разными режимами. Sentinel может работать в кластерном режиме или в локальном режиме, и разные режимы имеют разную логику ограничения тока. Поскольку в данном месте кластер не упоминается, сначала проводится анализ по локальному модулю.
private static boolean passLocalCheck(FlowRule rule, Context context, DefaultNode node, int acquireCount,
boolean prioritized) {
Node selectedNode = selectNodeByRequesterAndStrategy(rule, context, node);
if (selectedNode == null) {
return true;
}
return rule.getRater().canPass(selectedNode, acquireCount, prioritized);
}
В passLocalCheck() сначала получите соответствующий узел Node в соответствии с настроенной стратегией и источником запроса, а затем вызовите метод canPass() соответствующего узла для проверки.
В FlowRule есть TrafficShapingController, который представляет тип управления потоком, включая значение по умолчанию, прямой отказ, разминку и единую очередь, поэтому способ ограничения потока зависит от установленной политики.
4.4. TrafficShapingController
TrafficShapingController — это интерфейс, который в основном определяет стратегии управления трафиком и имеет три реализации, представляющие различные режимы обработки:
- DefaultController: стратегия обработки по умолчанию, которая напрямую отказывается обрабатывать
- RateLimiterController: очередь с постоянной скоростью
- WarmUpController: режим прогрева/холодного запуска
- WarmUpRateLimiterController: прогрев + равномерная очередь
В FlowRule будет переменный рейтер типа TrafficShapingController, который создается в соответствии с установленными правилами при обновлении правил следующим образом:
private static TrafficShapingController generateRater(/*@Valid*/ FlowRule rule) {
if (rule.getGrade() == RuleConstant.FLOW_GRADE_QPS) {
switch (rule.getControlBehavior()) {
case RuleConstant.CONTROL_BEHAVIOR_WARM_UP:
return new WarmUpController(rule.getCount(), rule.getWarmUpPeriodSec(),
ColdFactorProperty.coldFactor);
case RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER:
return new RateLimiterController(rule.getMaxQueueingTimeMs(), rule.getCount());
case RuleConstant.CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER:
return new WarmUpRateLimiterController(rule.getCount(), rule.getWarmUpPeriodSec(),
rule.getMaxQueueingTimeMs(), ColdFactorProperty.coldFactor);
case RuleConstant.CONTROL_BEHAVIOR_DEFAULT:
default:
// Default mode or unknown mode: default traffic shaping controller (fast-reject).
}
}
return new DefaultController(rule.getCount(), rule.getGrade());
}
5. Переход на более раннюю версию
Переход на более раннюю версию предохранителя Sentinel ограничит ресурс в вызывающей ссылке, когда ресурс находится в нестабильном состоянии, так что запрос быстро завершается ошибкой и не влияет на другие ресурсы и не вызывает каскадных ошибок. При понижении ресурса в следующем временном окне понижения обращения к ресурсу будут автоматически сброшены.
5.1. Стратегия понижения рейтинга
-
Среднее время ответа (DEGRADE_GRADE_RT): Когда 5 запросов продолжают поступать в течение 1 с, а среднее время ответа (второй уровень) в соответствующий момент превышает пороговое значение (количество, в мс), то в следующем временном окне (timeWindow в DegradeRule, in s), вызовы этого метода автоматически объединяются (выбрасывают DegradeException). Обратите внимание, что верхний предел RT по умолчанию для Sentinel составляет 4900 мс. Все, что превышает этот порог, будет считаться 4900 мс. Если вам нужно изменить этот верхний предел, вы можете настроить его, запустив элемент конфигурации -Dcsp.sentinel.statistic. макс.rt=xxx.
-
Соотношение исключений (DEGRADE_GRADE_EXCEPTION_RATIO): когда количество запросов ресурса в секунду >= 5, а отношение общего количества исключений в секунду к пропускной способности превышает пороговое значение (количество в DegradeRule), ресурс переходит в состояние ухудшения качества. , то есть в следующем временном окне (timeWindow в DegradeRule, в s) вызовы этого метода возвращаются автоматически. Пороговый диапазон для отношения аномалий составляет [0,0, 1,0], что соответствует 0–100 %.
-
Количество исключений (DEGRADE_GRADE_EXCEPTION_COUNT): когда количество исключений в ресурсе за последнюю минуту превысит пороговое значение, оно будет сброшено. Обратите внимание, что, поскольку статистическое временное окно находится на уровне минут, если timeWindow меньше 60 с, оно все еще может войти в состояние срабатывания после завершения состояния срабатывания.
5.2. DegradeRule
public class DegradeRule extends AbstractRule {
/**
* RT threshold or exception ratio threshold count.
*/
private double count;
/**
* Degrade recover timeout (in seconds) when degradation occurs.
*/
private int timeWindow;
/**
* Degrade strategy (0: average RT, 1: exception ratio, 2: exception count).
*/
private int grade = RuleConstant.DEGRADE_GRADE_RT;
/**
* 每秒钟连续进入的请求超的平均响应时间超过阀值的请求数
* Minimum number of consecutive slow requests that can trigger RT circuit breaking.
*
* @since 1.7.0
*/
private int rtSlowRequestAmount = RuleConstant.DEGRADE_DEFAULT_SLOW_REQUEST_AMOUNT;
/**
* 每秒钟连续进入的请求发生异常的请求数
* Minimum number of requests (in an active statistic time span) that can trigger circuit breaking.
*
* @since 1.7.0
*/
private int minRequestAmount = RuleConstant.DEGRADE_DEFAULT_MIN_REQUEST_AMOUNT;
}
DeGradeRule представляет правила предохранителя и перехода на более раннюю версию, а значения каждого поля:
- класс: Режим понижения класса автоматического выключателя, включая среднее время отклика, коэффициент аномалий и количество аномалий.
- count: порог деградации выключателя.
- timeWindow: продолжительность после понижения уровня автоматического выключателя.
- minRequestAmount: минимальное пороговое значение для неслияния и понижения последовательных входящих запросов в секунду.
- rtSlowRequestAmount: количество последовательных входящих запросов в секунду, среднее время ответа которых превышает пороговое значение.
5.3. DegradeSlot
DegradeSlot — это функциональный слот, отвечающий за обработку понижений уровня фьюза.Его код очень прост, потому что оценка конкретных понижений уровня фьюза реализована в DegradeRuleManager.
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args)
throws Throwable {
DegradeRuleManager.checkDegrade(resourceWrapper, context, node, count);
fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
5.4. DegradeRuleManager
DegradeRuleManager в основном отвечает за загрузку правил перехода на более раннюю версию фьюза и выполнение проверки на более раннюю версию фьюза для вызывающей записи.
/**
* 保存降级规则的缓存,以resource为key
*/
private static final Map<String, Set<DegradeRule>> degradeRules = new ConcurrentHashMap<>();
/**
* 规则改变处理器
*/
private static final RulePropertyListener LISTENER = new RulePropertyListener();
private static SentinelProperty<List<DegradeRule>> currentProperty
= new DynamicSentinelProperty<>();
static {
currentProperty.addListener(LISTENER);
}
DegradeRuleManager использует карту для сохранения правил фьюза и понижения, загруженных разными ресурсами, а также имеет собственный обработчик изменения правил.Логика загрузки и обновления правил аналогична другим функциональным слотам.
Как видно из вышеприведенного, когда запись попадает в DegradeSlot, она фактически вызывает метод checkDegrade() DegradeRuleManager для проверки предохранителя и перехода на более раннюю версию.
public static void checkDegrade(ResourceWrapper resource, Context context, DefaultNode node, int count)
throws BlockException {
Set<DegradeRule> rules = degradeRules.get(resource.getName());
if (rules == null) {
return;
}
for (DegradeRule rule : rules) {
if (!rule.passCheck(context, node, count)) {
throw new DegradeException(rule.getLimitApp(), rule);
}
}
}
Метод checkDegrade() сначала получает соответствующее текущее ограничивающее правило в соответствии с ресурсом, а затем вызывает метод правила passCheck() для его проверки в цикле.Если проверка не пройдена, генерируется исключение DegradeException.
Поэтому конкретная логика проверки реализована в passCheck() в DegradeRule Конкретный код выглядит следующим образом:
public boolean passCheck(Context context, DefaultNode node, int acquireCount, Object... args) {
//如果是在限流的窗口时间内,直接降级
if (cut.get()) {
return false;
}
//降级只针对resource维度进行,不区分context,不区分orgin,在statisticSlot中会在defaultNode里面对clusterNode进行累加
ClusterNode clusterNode = ClusterBuilderSlot.getClusterNode(this.getResource());
if (clusterNode == null) {
return true;
}
if (grade == RuleConstant.DEGRADE_GRADE_RT) {
//case1:rt降级
//平均响应时间
double rt = clusterNode.avgRt();
//平均响应时间小于设置的阀值,直接通过
if (rt < this.count) {
passCount.set(0);
return true;
}
//请求数自增,如果请求数小于设置的值5,直接通过
if (passCount.incrementAndGet() < rtSlowRequestAmount) {
return true;
}
} else if (grade == RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO) {
//case2 异常比例
double exception = clusterNode.exceptionQps();
double success = clusterNode.successQps();
double total = clusterNode.totalQps();
//如果请求总数小于设置的每秒允许的最小请求数量,直接返回
if (total < minRequestAmount) {
return true;
}
double realSuccess = success - exception;
if (realSuccess <= 0 && exception < minRequestAmount) {
return true;
}
if (exception / success < count) {
return true;
}
} else if (grade == RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT) {
//case3: 异常数
//统计异常总数的时间窗口是分钟级别的,如果timeWindow的时间小于60s,会以60s进行熔断
double exception = clusterNode.totalException();
//如果异常数小于指定的值,直接返回
if (exception < count) {
return true;
}
}
//开启一个定时任务,在指定的窗口时间后执行,将请求数设置为0,降级标识设置为false
if (cut.compareAndSet(false, true)) {
ResetTask resetTask = new ResetTask(this);
pool.schedule(resetTask, timeWindow, TimeUnit.SECONDS);
}
return false;
}
Логика функции passCheck() относительно проста. В основном она оценивает, достигнут ли порог настройки понижения на основе данных, полученных ранее. Если она превышается, она возвращает false и запускает поток. Его функция состоит в том, чтобы непосредственно обрабатывать последующий запрос. как указанное timeWindow после обработки перехода на более раннюю версию.
6. Резюме
В этой статье в основном анализируется принцип реализации часто используемых функциональных слотов в Sentinel, а также рассматривается текущая стратегия Sentinel по ограничению и деградации.
7. Ссылки
управление потоком
Слияние понижения
Система адаптивного ограничения тока
Управление черным и белым списком