Я думаю, что система адаптивного ограничения тока по-прежнему является относительно практичной и ценной функцией в реальной производственной среде.В реальной производственной среде нам на самом деле трудно иметь четкое представление о нашей системе, например, о количестве запросов в секунду, которое может быть выполнено. время отклика на запросы и другие показатели. Конечно, вы можете сказать, что мы можем провести стресс-тестирование системы для получения соответствующих показателей, но эти показатели на самом деле связаны с тестовым сервером, средой размещения службы, нагрузкой и другими факторами в данный момент, поэтому мы можем получить только индикаторы измерения стресса Общее понимание в сочетании с соответствующим опытом для оценки производительности системы. Поэтому, если вы не уверены в количестве запросов в секунду, которое может выдержать система, и сосредоточены на балансировке производительности системы с точки зрения нагрузки на систему, адаптивное ограничение тока на самом деле является хорошим выбором.
Самоадаптация системы, «система» просто означает выбор нескольких показателей системы, «адаптивная» — это использование определенного алгоритма для расчета результата на основе этих показателей, а затем сравнение результата с заданным пороговым значением, чтобы определить, является ли необходимо запустить механизм ограничения тока. В качестве критериев оценки в Sentinel выбраны следующие системные индикаторы, которые можно установить независимо или одновременно:
- системная нагрузка
- использование процессора
- Среднее время ответа на запрос
- Количество одновременных потоков
- Входящие запросы в секунду
В настоящее время адаптация запускается в соответствии с нагрузкой на систему. Он заимствует идею алгоритма TCP BBR (вы можете составить свое собственное мнение), и его цель — сделать так, чтобы ваша система по-прежнему имела высокую пропускную способность в условиях высокой нагрузки. В реализации Sentinel фактически происходит ситуация загрузки системы сбора времени, если значение нагрузки выше установленного порога, сработает проверка BBR, о которой подробно будет рассказано далее. Адаптивное ограничение тока предназначено для входящего трафика, то есть entryType ресурса — EntryType.IN. На самом деле ограничений на этот вид настройки нет, использовать можно на любом ресурсе, конечно, лучше всего все же на входе трафика в систему. На практике я создам перехватчик, чтобы весь трафик проходил через этот перехватчик, чтобы в этом перехватчике можно было выполнять адаптивное дросселирование потока.
Вышеприведенное кратко описывает некоторые ситуации системного адаптивного ограничения тока.Если вам нужно подробно разобраться в соответствующем контексте, вы можете обратиться к официальномуДокументация. Далее будет введен исходный код для детального анализа. Адаптивное ограничение тока системы выполняется в классе метода входа в классе SystemSlot.
SpiOrder(-5000)
public class SystemSlot extends AbstractLinkedProcessorSlot<DefaultNode> {
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
boolean prioritized, Object... args) throws Throwable {
//系统规则校验
SystemRuleManager.checkSystem(resourceWrapper);
fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
@Override
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
fireExit(context, resourceWrapper, count, args);
}
}
Введите метод SystemRuleManager.checkSystem:
public static void checkSystem(ResourceWrapper resourceWrapper) throws BlockException {
if (resourceWrapper == null) {
return;
}
//系统全局检测开关是否开启
if (!checkSystemStatus.get()) {
return;
}
// 判断是否为入口流量
if (resourceWrapper.getEntryType() != EntryType.IN) {
return;
}
// 获取当前总的qps
double currentQps = Constants.ENTRY_NODE == null ? 0.0 : Constants.ENTRY_NODE.successQps();
//如果大于了设置了系统qps,则抛出异常
if (currentQps > qps) {
throw new SystemBlockException(resourceWrapper.getName(), "qps");
}
//如果当前系统的线程数大于设置值,则抛出异常
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");
}
// 获取当前系统负载,如果当前负载大于设置值,则会根据BBR算法来进一步判断是否需要限流
if (highestSystemLoadIsSet && getCurrentSystemAvgLoad() > highestSystemLoad) {
if (!checkBbr(currentThread)) {
throw new SystemBlockException(resourceWrapper.getName(), "load");
}
}
//如果当前系统cpu使用值大于设置值,则抛出异常
if (highestCpuUsageIsSet && getCurrentCpuUsage() > highestCpuUsage) {
throw new SystemBlockException(resourceWrapper.getName(), "cpu");
}
}
Проверка BBR делается в методе checkBbr Код на самом деле очень простой:
private static boolean checkBbr(int currentThread) {
if (currentThread > 1 &&
currentThread > Constants.ENTRY_NODE.maxSuccessQps() * Constants.ENTRY_NODE.minRt() / 1000) {
return false;
}
return true;
}
Как видно из приведенного выше кода, Sentinel сравнивает текущее количество потоков с произведением максимального количества запросов в секунду и минимального времени отклика системы. Что касается того, почему это сделано, вы можете обратиться к официальной документации. Эта связь объясняется здесь из самой формулы. Мы предполагаем, что maxQps = 100, minRt = 10 мс, если система работает с этим показателем, количество необходимых потоков в секунду является их произведением 10 = 100 * 10 / 1000, этот результат представляетМаксимальная пропускная способность системы. Если количество запущенных в данный момент потоков превышает это значение, система достигла своего «предела». Нагрузка на систему и связанные с ней показатели производительности на самом деле меняются.Sentinel собирает соответствующие показатели системы через временной интервал задачи 1 с. Код определяет класс SystemStatusListener, который реализует интерфейс Runable и отвечает за сбор системных метрик:
private static SystemStatusListener statusListener = null;
private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1,
new NamedThreadFactory("sentinel-system-status-record-task", true));
static {
statusListener = new SystemStatusListener();
//当前类创建的时候就会采集系统指标,间隔1s
scheduler.scheduleAtFixedRate(statusListener, 0, 1, TimeUnit.SECONDS);
}
Глядя на метод запуска SystemStatusListener, вы можете узнать, какие индикаторы собираются.Получение этих индикаторов на самом деле зависит от интерфейса, предоставляемого JMX.
@Override
public void run() {
try {
//获取操作系统相关信息
OperatingSystemMXBean osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class);
currentLoad = osBean.getSystemLoadAverage();
//获取系统负载
double systemCpuUsage = osBean.getSystemCpuLoad();
//获取jvm相关信息
RuntimeMXBean runtimeBean = ManagementFactory.getPlatformMXBean(RuntimeMXBean.class);
//jvm进程占用cpu的时间
long newProcessCpuTime = osBean.getProcessCpuTime();
//jvm启动时间
long newProcessUpTime = runtimeBean.getUptime();
//可用处理器数量
int cpuCores = osBean.getAvailableProcessors();
//两次采集间隔间,jvm占用的cpu时间
long processCpuTimeDiffInMs = TimeUnit.NANOSECONDS
.toMillis(newProcessCpuTime - processCpuTime);
//两次采集间隔间,jvm运行时间
long processUpTimeDiffInMs = newProcessUpTime - processUpTime;
//获取jvm进程的cup使用率
double processCpuUsage = (double) processCpuTimeDiffInMs / processUpTimeDiffInMs / cpuCores;
processCpuTime = newProcessCpuTime;
processUpTime = newProcessUpTime;
//取系统和jvm cpu使用率中的较大者
currentCpuUsage = Math.max(processCpuUsage, systemCpuUsage);
} catch (Throwable e) {
RecordLog.warn("[SystemStatusListener] Failed to get system metrics from JMX", e);
}
}
Как видно из приведенного выше кода, существует только два индикатора, которые Sentinel получает от системы: загрузка системы и использование чашки. Тут у вас может возникнуть вопрос.При получении загрузки системы берется большая из системы и jvm. По здравому смыслу, jvm это просто процесс в системе, и нагрузка на систему должна быть больше, чем нагрузка на jvm.Почему бы просто не получить нагрузку на систему напрямую? На самом деле причина в том, что показатели нашей системы собираются дискретно, возможно, что в момент сбора нагрузка на систему как раз относительно невелика, а в период может быть высокая нагрузка, полученные значения не являются репрезентативными, поэтому принимается больший из двух, который имеет лучшее представительство.
Приведенный выше код представляет собой весь процесс адаптивного ограничения тока Ключом к адаптивности является выполнение проверки BBR, когда нагрузка системы превышает установленный порог.