admin 管理员组文章数量: 887021
入门篇
前言
本文会从简单的demo使用,来跟踪代码,本文的内容主要介绍一个demo, 然后跟踪一下这个demo运行之前,sentinel做了哪些准备工作。
注意: 笔者使用的sentinel版本都是基于官方1.8.0版本
demo
引入pom文件
<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-core</artifactId><version>1.8.0</version>
</dependency>
test类
package com.test.xx;import java.util.ArrayList;
import java.util.List;import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;/*** @author yunhe.zhang* @version Test.java, v 0.1 2021-03-19 10:00 yunhe.zhang Exp $$*/
public class Test {public static void main(String[] args) {// 配置规则.initFlowRules();while (true) {// 1.5.0 版本开始可以直接利用 try-with-resources 特性try (Entry entry = SphU.entry("HelloWorld")) {// 被保护的逻辑System.out.println("hello world");} catch (BlockException ex) {// 处理被流控的逻辑 , 如果发生流控,那么就会走到这里System.out.println("blocked!");}}}private static void initFlowRules(){List<FlowRule> rules = new ArrayList<>();FlowRule rule = new FlowRule();rule.setResource("HelloWorld");rule.setGrade(RuleConstant.FLOW_GRADE_QPS);// Set limit QPS to 20.rule.setCount(20);rules.add(rule);FlowRuleManager.loadRules(rules);}
}
引入上面的这个pom, 然后写一段代码,这个demo就可以运行了,其实已经可以看到一些效果了。
这篇文章的重点不在于讲解sentinel怎么工作的,而是讲一下,他在工作之前做了哪些初始化工作。
Env
上面的代码中,在while循环里面执行的是这个方法Entry entry = SphU.entry("HelloWorld")
, 我们就从这个为入口,
public static Entry entry(String name, EntryType trafficType, int batchCount, Object... args)throws BlockException {return Env.sph.entry(name, trafficType, batchCount, args);
}
Env.sph
这个对象很重要,限流的所有核心逻辑都在这个里面, 下面我们看一下Env类com.alibaba.csp.sentinel.Env
public class Env {public static final Sph sph = new CtSph();static {// If init fails, the process will exit. (意思是如果初始化失败,那么进程会退出)InitExecutor.doInit();}}
代码非常的简单,sph的初始化了一个实例 new CtSph()
,
我们看一下InitExecutor.doInit()
这个里面做了哪些初始化工作
/*** 根据SPI机制加载已经注册的功能模块,并按照注册的顺序执行*/
public final class InitExecutor {private static AtomicBoolean initialized = new AtomicBoolean(false);/*** If one {@link InitFunc} throws an exception, the init process* will immediately be interrupted and the application will exit.** The initialization will be executed only once.*/public static void doInit() {// 使用cas机制,保证初始化动作仅执行一次if (!initializedpareAndSet(false, true)) {return;}try {// 通过SPI机制,获取META-INF文件夹下面,services文件夹下面的`com.alibaba.csp.sentinel.init.InitFunc`ServiceLoader<InitFunc> loader = ServiceLoaderUtil.getServiceLoader(InitFunc.class);// 循环获取到的功能模块,进行初始化,同时进行排序List<OrderWrapper> initList = new ArrayList<OrderWrapper>();for (InitFunc initFunc : loader) {RecordLog.info("[InitExecutor] Found init func: " + initFunc.getClass().getCanonicalName());// 进行排序,插入到一个list里面去保存起来insertSorted(initList, initFunc);}for (OrderWrapper w : initList) {// 执行初始化动作,各个实现类,各做各的w.func.init();RecordLog.info(String.format("[InitExecutor] Executing %s with order %d",w.func.getClass().getCanonicalName(), w.order));}} catch (Exception ex) {RecordLog.warn("[InitExecutor] WARN: Initialization failed", ex);ex.printStackTrace();} catch (Error error) {RecordLog.warn("[InitExecutor] ERROR: Initialization failed with fatal error", error);error.printStackTrace();}}private static void insertSorted(List<OrderWrapper> list, InitFunc func) {// 获取排序值int order = resolveOrder(func);int idx = 0;// 这里进行比较排序值,从小到大依次排列for (; idx < list.size(); idx++) {if (list.get(idx).getOrder() > order) {break;}}list.add(idx, new OrderWrapper(order, func));}private static int resolveOrder(InitFunc func) {// 类中是否存在排序注解,不存在则取一个默认值 Integer.MAX_VALUEif (!func.getClass().isAnnotationPresent(InitOrder.class)) {return InitOrder.LOWEST_PRECEDENCE;} else {// 存在就取自己设置的return func.getClass().getAnnotation(InitOrder.class).value();}}private InitExecutor() {}// 排序对象private static class OrderWrapper {private final int order;private final InitFunc func;OrderWrapper(int order, InitFunc func) {this.order = order;this.func = func;}int getOrder() {return order;}InitFunc getFunc() {return func;}}
}
步骤大致说明:
- 通过SPI机制,获取META-INF文件夹下面,services文件夹下面的
com.alibaba.csp.sentinel.init.InitFunc
, 目前在源码里面找到的,com.alibaba.csp.sentinel.init.InitFunc
文件里, 默认仅提供了一个类com.alibaba.csp.sentinel.metric.extension.MetricCallbackInit
, 这个是限流成功,失败的时候做数据统计的。 通过多少,拒绝多少,都有统计。 - 对获取到的功能模块进行排序处理,从小到大的一次排列好。
sentinel-core里面只有一个类初始化,但是如果引入了其他模块的话,就会有很多了,下面列举一下
引入sentinel-transport
, 开启客户端和控制台的连接
-
com.alibaba.csp.sentinel.transport.init.CommandCenterInitFunc
初始化所有客户端上报控制台的命令连接,控制台上收集到的信息,都是通过这个来进行触发的
-
com.alibaba.csp.sentinel.transport.init.HeartbeatSenderInitFunc
设置心跳线程,对dashboard控制台发起心跳,如果不设置的话,是5秒一次
引入sentinel-cluster
, 使用sentinel的集权限流
com.alibaba.csp.sentinel.cluster.client.init.DefaultClusterClientInitFunc
用与初始化集群限流客户端的所需资源;
-
com.alibaba.csp.sentinel.cluster.server.init.DefaultClusterServerInitFunc
用与初始化集群限流服务端的所需资源;
引入sentinel-extension > sentinel-parameter-flow-control
-
com.alibaba.csp.sentinel.init.ParamFlowStatisticSlotCallbackInit
用于初始化参数流控回调.
其实看了这么多源码,很多开源的项目都喜欢用SPI机制,这是一个让人很爽的机制,有兴趣的朋友可以研究研究。
sharedCode源码交流群,欢迎喜欢阅读源码的朋友加群,添加下面的微信, 备注”加群“ 。
本文标签: 入门篇
版权声明:本文标题:入门篇 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/free/1698370798h296229.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论