SystemSlot
则通过系统的状态,例如 load1 等,来控制总的入口流量,对QPS,RT,最大线程数等做限流。
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);
}
}
SystemSlot
依赖于SystemRuleManager
来做检查。
检查规则如下:
- 判断是否启用SystemRule,如果没有配置,checkSystemStatus为=false,若配置,则为true。
- 判断流量是外部请求内部,还是内部请求外部,若为内部请求外部,则直接返回,不做检查。
- 比较QPS,比较当前线程数,比较响应时间,比较CPU使用率等,判断是否需要限流。
public static void checkSystem(ResourceWrapper resourceWrapper) throws BlockException {
// 检查系统状态是否为false,如果为false,则代表不检查
// 如果不配置SystemRule,则不检查
if (!checkSystemStatus.get()) {
return;
}
// 系统检查状态,只检查外部调内部的接口状态,IN,内部调用外部接口不检查
if (resourceWrapper.getType() != EntryType.IN) {
return;
}
// 获取当前系统的QPS,根据ClusterNode的successQps计算 successQps总数/时间 每秒成功的记录
double currentQps = Constants.ENTRY_NODE == null ? 0.0 : Constants.ENTRY_NODE.successQps();
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");
}
// load. BBR algorithm.
if (highestSystemLoadIsSet && getCurrentSystemAvgLoad() > highestSystemLoad) {
if (!checkBbr(currentThread)) {
throw new SystemBlockException(resourceWrapper.getName(), "load");
}
}
// CPU使用率超过限制
if (highestCpuUsageIsSet && getCurrentCpuUsage() > highestCpuUsage) {
if (!checkBbr(currentThread)) {
throw new SystemBlockException(resourceWrapper.getName(), "cpu");
}
}
}
配置从哪里来?
在 SystemRuleManager
中,有一个静态方法(loadRules(List<SystemRule> rules)
)去初始化SystemRule配置。
public static void loadRules(List<SystemRule> rules) {
currentProperty.updateValue(rules);
}
而在更新currentProperty的时候,实质是通知观察者去更新,这里使用的是观察者模式
public class DynamicSentinelProperty<T> implements SentinelProperty<T> {
//观察者
protected Set<PropertyListener<T>> listeners = Collections.synchronizedSet(new HashSet<PropertyListener<T>>());
//更新值
@Override
public boolean updateValue(T newValue) {
//如果两个值一样,则返回false,不修改
if (isEqual(value, newValue)) {
return false;
}
value = newValue;
//通知各个观察者
for (PropertyListener<T> listener : listeners) {
listener.configUpdate(newValue);
}
return true;
}
//判断两个对象是否一致
private boolean isEqual(T oldValue, T newValue) {
if (oldValue == null && newValue == null) {
return true;
}
if (oldValue == null) {
return false;
}
return oldValue.equals(newValue);
}
public void close() {
listeners.clear();
}
}
这里的观察者为SystemPropertyListener
,在SystemRuleManager
的静态方法区已经添加进去。
public class SystemRuleManager {
//观察者,当systemRule配置发生变更时,会通知该Listener
private final static SystemPropertyListener listener = new SystemPropertyListener();
static {
checkSystemStatus.set(false);
statusListener = new SystemStatusListener();
scheduler.scheduleAtFixedRate(statusListener, 5, 1, TimeUnit.SECONDS);
//添加观察者
currentProperty.addListener(listener);
}
}
而在SystemPropertyListener
更新的时候,会先关闭系统检查,当配置修改完成之后,再启用。
static class SystemPropertyListener extends SimplePropertyListener<List<SystemRule>> {
@Override
public void configUpdate(List<SystemRule> rules) {
//恢复到默认状态
restoreSetting();
if (rules != null && rules.size() >= 1) {
for (SystemRule rule : rules) {
//加载配置
loadSystemConf(rule);
}
} else {
checkSystemStatus.set(false);
}
}
//重置配置信息
protected void restoreSetting() {
checkSystemStatus.set(false);
// should restore changes
highestSystemLoad = Double.MAX_VALUE;
highestCpuUsage = Double.MAX_VALUE;
maxRt = Long.MAX_VALUE;
maxThread = Long.MAX_VALUE;
qps = Double.MAX_VALUE;
highestSystemLoadIsSet = false;
maxRtIsSet = false;
maxThreadIsSet = false;
qpsIsSet = false;
}
}
修改则判断是否小于默认配置,由于之前已经重新初始化过了,所以如果有修改,肯定会比默认的值小。
public static void loadSystemConf(SystemRule rule) {
boolean checkStatus = false;
if (rule.getHighestSystemLoad() >= 0) {
highestSystemLoad = Math.min(highestSystemLoad, rule.getHighestSystemLoad());
highestSystemLoadIsSet = true;
checkStatus = true;
}
if (rule.getHighestCpuUsage() >= 0) {
highestCpuUsage = Math.min(highestCpuUsage, rule.getHighestCpuUsage());
highestCpuUsageIsSet = true;
checkStatus = true;
}
if (rule.getAvgRt() >= 0) {
maxRt = Math.min(maxRt, rule.getAvgRt());
maxRtIsSet = true;
checkStatus = true;
}
if (rule.getMaxThread() >= 0) {
maxThread = Math.min(maxThread, rule.getMaxThread());
maxThreadIsSet = true;
checkStatus = true;
}
if (rule.getQps() >= 0) {
qps = Math.min(qps, rule.getQps());
qpsIsSet = true;
checkStatus = true;
}
checkSystemStatus.set(checkStatus);
}
配置加载完毕,如果有SystemRule配置,则将checkSystemStatus改为true。