Sentine 源码分析之--AuthoritySlot、SystemSlot、GatewayFlowSlot

前言:

上一篇我对 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);
		}
	}
}

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

  • 17
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
sentinel-dashboard-1.8.2是一个开源的项目,用于监控和管理Sentinel的规则、实时流量、集群节点等信息。它是一个基于Java开发的Web应用程序,采用了Spring Boot框架和Vue.js前端框架。 首先,sentinel-dashboard-1.8.2源码的结构非常清晰和模块化。它分为后端和前端两部分,后端代码位于sentinel-dashboard模块,前端代码位于sentinel-dashboard-frontend模块。这种结构使得代码的维护和扩展变得更加容易。 在后端部分,sentinel-dashboard-1.8.2源码中包含了一系列的Java类,用于实现Sentinel的规则管理、实时数据统计和集群节点的管理等功能。它提供了RESTful的接口用于前端页面的数据获取和交互。这些Java类使用了Spring框架提供的注解和特性,使得代码简洁、易读和易于维护。 在前端部分,sentinel-dashboard-1.8.2源码中的前端代码采用了Vue.js框架进行开发。它使用了一系列的组件来实现不同的功能模块,如规则管理、流量统计、集群节点管理等。前端页面具有良好的交互性和可视化效果,可以方便地进行规则的配置和流量的监控。 另外,sentinel-dashboard-1.8.2源码还使用了一些开源的技术和库,如Redis、MyBatis等,以提供更好的性能和扩展性。 总结来说,sentinel-dashboard-1.8.2源码是一个功能丰富、结构清晰和易于维护的开源项目。通过深入研究和理解源码,开发人员可以对Sentinel的规则管理和流量监控等核心功能有更深入的了解,并根据自己的需求进行二次开发和定制化操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值