0
点赞
收藏
分享

微信扫一扫

Python爬虫(8)

前言:

上一篇我对 Sentinel 中统计数据部分的 NodeSelectorSlot、ClusterBuilderSlot、StatisticSlot 的相关源码进行了分析,本篇我们开始分析规则相关的源码。

Sentinel 系列文章传送门:

Sentinel 初步认识及使用

Sentinel 核心概念和工作流程详解

Spring Cloud 整合 Nacos、Sentinel、OpenFigen 实战【微服务熔断降级实战】

Sentinel 源码分析入门【Entry、Chain、Context】

Sentine 源码分析之–NodeSelectorSlot、ClusterBuilderSlot、StatisticSlot

在这里插入图片描述

AuthoritySlot

关于 AuthoritySlot 官方是如下描述:

很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源访问控制(黑白名单控制)的功能。来源访问控制根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。

AuthoritySlot 授权规则配置如下:
在这里插入图片描述

代码中的规则详情如下:
在这里插入图片描述

AuthoritySlot#entry 方法源码解析

AuthoritySlot#entry 方法还是老套路,执行一个校验方法,然后执行下一个 Sllot,重点关注校验方法。

//com.alibaba.csp.sentinel.slots.block.authority.AuthoritySlot#entry
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args)
	throws Throwable {
	//检查黑白名单权限
	checkBlackWhiteAuthority(resourceWrapper, context);
	//进入下一个 slot
	fireEntry(context, resourceWrapper, node, count, prioritized, args);
}

AuthoritySlot#checkBlackWhiteAuthority 方法源码解析

AuthoritySlot#checkBlackWhiteAuthority 方法先是对规则和当前资源的规则进行为空判断,如果为空直接返回,否则循环遍历所有规则执行校验动作。

//com.alibaba.csp.sentinel.slots.block.authority.AuthoritySlot#checkBlackWhiteAuthority
void checkBlackWhiteAuthority(ResourceWrapper resource, Context context) throws AuthorityException {
	//获取所有权限规则
	Map<String, Set<AuthorityRule>> authorityRules = AuthorityRuleManager.getAuthorityRules();
	//authorityRules 为空判断
	if (authorityRules == null) {
		return;
	}
	//根据当前资源的 name 获取规则
	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);
		}
	}
}

ConfigCacheService#dumpBeta 方法源码解析

AuthorityRuleChecker#passCheck 方法主要做了一下几件事:

  • 对请求来源 orgin 和 黑白名单为空判断,如果为空则直接返回true,规则通过。
  • 判断请求来源是否在黑白名单中,如果在还会进行完全匹配,如果完全匹配也满足,就认为当前请求来源在黑白名单中。
  • 对规则策略进行判断,是黑名单类型且完全匹配到则返回规则不通过,是白名单类型且没有完全匹配到返回规则不通过,其他情况返回规则通过。

规则配置项解释如下:

  • resource:资源名,限流规则的作用对象。
  • limitApp:对应的黑白名单,不同 origin 用英文逗号分隔,如 app1,app2,app3。
  • strategy:规则策略,AUTHORITY_WHITE 为白名单模式,AUTHORITY_BLACK 为黑名单模式,默认为白名单模式。

//com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleChecker#passCheck
static boolean passCheck(AuthorityRule rule, Context context) {
	//获取请求来源 orgin
	String requester = context.getOrigin();

	// Empty origin or empty limitApp will pass.
	//请求来源 orgin 为空 或者 对应的黑白名单为空  都直接返回
	if (StringUtil.isEmpty(requester) || StringUtil.isEmpty(rule.getLimitApp())) {
		return true;
	}

	// Do exact match with origin name.
	//getLimitApp 就是黑白名单 indexOf 判断 请求来源是否在 黑白名单中
	int pos = rule.getLimitApp().indexOf(requester);
	boolean contain = pos > -1;

	if (contain) {
		//在黑白名单中 还需要进一步判断
		boolean exactlyMatch = false;
		//黑白名单数组
		String[] appArray = rule.getLimitApp().split(",");
		for (String app : appArray) {
			//进行 equals 完全匹配
			if (requester.equals(app)) {
				//完全匹配到了
				exactlyMatch = true;
				//终止循环
				break;
			}
		}
		//完全匹配的值 赋值给 contain
		contain = exactlyMatch;
	}

	//获取规则策略 也就是 到底是黑明单  还是白名单
	int strategy = rule.getStrategy();
	if (strategy == RuleConstant.AUTHORITY_BLACK && contain) {
		//是黑名单 且完全匹配到了 返回 false
		return false;
	}

	if (strategy == RuleConstant.AUTHORITY_WHITE && !contain) {
		//是白名单 且没有完全匹配到 返回 false
		return false;
	}

	return true;
}

SystemSlot

SystemSlot 是系统级限流器。

SystemSlot 系统规则配置如下:
在这里插入图片描述

SystemSlot#entry 方法源码解析

SystemSlot#entry 方法同样是老套路,进行规则校验,执行下一个 Slot,我们重点关注规则校验。

//com.alibaba.csp.sentinel.slots.system.SystemSlot#entry
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
				  boolean prioritized, Object... args) throws Throwable {
	//系统规则校验
	SystemRuleManager.checkSystem(resourceWrapper);
	//进入下一个 slot
	fireEntry(context, resourceWrapper, node, count, prioritized, args);
}

SystemRuleManager#checkSystem 方法源码解析

SystemRuleManager#checkSystem 方法主要做了如下几件事:

  • 校验资源是否为空。
  • 检查系统限流开关是否打开。
  • 对资源类型进行校验,系统限流只校验入口流量。
  • 对 QPS 、线程数和 maxRt 进行校验,如果大于系统阀值,则直接抛出异常。
  • 对 CPU 使用率和系统负载进行校验,如果大于系统阀值,则直接抛出异常。

//com.alibaba.csp.sentinel.slots.system.SystemRuleManager#checkSystem
public static void checkSystem(ResourceWrapper resourceWrapper) throws BlockException {
	//资源包装器为空判断
	if (resourceWrapper == null) {
		return;
	}
	// Ensure the checking switch is on.
	//检查开关是否打开 如果没有打开 直接返回
	if (!checkSystemStatus.get()) {
		return;
	}

	// for inbound traffic only
	//只对入口资源进行校验 其他资源直接返回
	if (resourceWrapper.getEntryType() != EntryType.IN) {
		return;
	}

	// total qps
	//获取 ClusterNode 记录的成功的 QPS
	double currentQps = Constants.ENTRY_NODE == null ? 0.0 : Constants.ENTRY_NODE.successQps();
	//判断是否大于 Double.MAX_VALUE 大于则抛出异常
	if (currentQps > qps) {
		throw new SystemBlockException(resourceWrapper.getName(), "qps");
	}

	// total thread
	//获取 ClusterNode 记录的 线程数
	int currentThread = Constants.ENTRY_NODE == null ? 0 : Constants.ENTRY_NODE.curThreadNum();
	//线程数大于 Long.MAX_VALUE 抛出异常
	if (currentThread > maxThread) {
		throw new SystemBlockException(resourceWrapper.getName(), "thread");
	}
	//获取 ClusterNode 记录的平均 rt
	double rt = Constants.ENTRY_NODE == null ? 0 : Constants.ENTRY_NODE.avgRt();
	//最大 rt 大于 Long.MAX_VALUE  抛出异常
	if (rt > maxRt) {
		throw new SystemBlockException(resourceWrapper.getName(), "rt");
	}

	// load. BBR algorithm.
	//全局系统负载校验
	//highestSystemLoadIsSet 默认 false
	//getCurrentSystemAvgLoad() 默认返回 -1
	//highestSystemLoad = Double.MAX_VALUE;
	//默认情况下是进入不了 if 的
	if (highestSystemLoadIsSet && getCurrentSystemAvgLoad() > highestSystemLoad) {
		if (!checkBbr(currentThread)) {
			throw new SystemBlockException(resourceWrapper.getName(), "load");
		}
	}

	// cpu usage
	//全局 CPU 校验
	//highestCpuUsageIsSet 默认 false
	//getCurrentCpuUsage() 默认返回 -1
	//highestCpuUsage = Double.MAX_VALUE;
	//默认情况下是进入不了 if 的
	if (highestCpuUsageIsSet && getCurrentCpuUsage() > highestCpuUsage) {
		throw new SystemBlockException(resourceWrapper.getName(), "cpu");
	}
}

SystemRuleManager#checkBbr 方法源码解析

SystemRuleManager#checkBbr 方法判断 ClusterNode 中记录的线程数大于系统最大负载则范湖规则不通过。

//com.alibaba.csp.sentinel.slots.system.SystemRuleManager#checkBbr
private static boolean checkBbr(int currentThread) {
	//currentThread ClusterNode 中记录的线程数
	if (currentThread > 1 &&
		currentThread > Constants.ENTRY_NODE.maxSuccessQps() * Constants.ENTRY_NODE.minRt() / 1000) {
		//ClusterNode 中记录的线程数 大于 请求成功的 QPS 乘以 最小 RT 除以 1000 得到的是系统最大负载
		//如果 线程数已经大于最大负载了 直接返回 false
		return false;
	}
	return true;
}

GatewayFlowSlot

Sentinel 支持 API 网关限流。

GatewayFlowSlot#entry 方法源码解析

GatewayFlowSlot#entry 方法只做了两件事,规则校验和进入下一个 Slot,我们重点关注规则校验。

//com.alibaba.csp.sentinel.adapter.gateway.common.slot.GatewayFlowSlot#entry
@Override
public void entry(Context context, ResourceWrapper resource, DefaultNode node, int count,
				  boolean prioritized, Object... args) throws Throwable {
	//检查网关参数 也就是规则校验
	checkGatewayParamFlow(resource, count, args);
	//进入下一个 slot
	fireEntry(context, resource, node, count, prioritized, args);
}

GatewayFlowSlot#checkGatewayParamFlow 方法源码解析

GatewayFlowSlot#checkGatewayParamFlow 方法首先对参数进行校验,如果参数为空则直接返回无需进行规则校验,否则获取规则对规则为空进行判断,如果规则不为空则执行规则校验,具体的规则校验我们会在在下一篇 ParamFlowSlot 中详细分析。

//com.alibaba.csp.sentinel.adapter.gateway.common.slot.GatewayFlowSlot#checkGatewayParamFlow
private void checkGatewayParamFlow(ResourceWrapper resourceWrapper, int count, Object... args)
	throws BlockException {
	//参数为空判断
	if (args == null) {
		return;
	}
	//获取参数规则
	List<ParamFlowRule> rules = GatewayRuleManager.getConvertedParamRules(resourceWrapper.getName());
	//规则为空判断
	if (rules == null || rules.isEmpty()) {
		return;
	}
	//遍历规则
	for (ParamFlowRule rule : rules) {
		// Initialize the parameter metrics.
		//初始化参数指标
		ParameterMetricStorage.initParamMetricsFor(resourceWrapper, rule);
		//执行规则校验
		if (!ParamFlowChecker.passCheck(resourceWrapper, rule, count, args)) {
			//校验不通过 抛出异常
			String triggeredParam = "";
			if (args.length > rule.getParamIdx()) {
				Object value = args[rule.getParamIdx()];
				triggeredParam = String.valueOf(value);
			}
			throw new ParamFlowException(resourceWrapper.getName(), triggeredParam, rule);
		}
	}
}

如有不正确的地方请各位指出纠正。

举报

相关推荐

0 条评论