之前介绍过dashboard模块也引入的sentinel的核心模块sentinel-core,所以这里通过启动dashboard来分析sentinel在系统初次加载过程中做了什么?
本文基于:1.3.0-GA版本
一、启动dashboard项目
dashboard项目通过CommonFilter过滤器实现对资源的保护的。
image.png启动项目后,访问首页,默认localhost:8080
在过滤器CommonFilter就会拦截请求的资源,如图。
这个时候就进入到sentinel的核心模块了。
二、进入ContextUtil
首先执行ContextUtil静态快内容,如图:
image.png
1、首先获取默认的Context名称:sentinel_default_context;Context是一次调用的上下文内容,主要包括:name,entranceNode(调用树资源入口),curEntry(当前实体)等信息,关于这个Context上下文、EntranceNode等后续再介绍。
2、构建一个EntranceNode节点node。
3、构建一个跟节点ROOT,并增加一个字节点node;见第三步Constants
4、把资源信息放到一个 contextNameNodeMap,后面进入资源名称相同直接可以从map中获取。
三、进入Constants
Constants是一个常量类,这里我们主要注意的是断点处,如图:
image.png1、在构建一个DefaultNode,用的是new EntranceNode(ResourceWrapper,ClusterNode)方法,
2、EntranceNode是DefaultNode的子类,
3、ResourceWrapper是一个资源包装器,这里用的通用的StringResourceWrapper包装器,
4、构建一个ClusterNode用的是Env类的nodeBuilder的静态变量,通过DefaultNodeBuilder获取。
四、进入Env
image.png注意到静态块内容,Env类在初始化会加载。来到InitExecutor类
五、进入InitExecutor
这个就是Sentinel的加载的核心了。
image.png在doInit中:
1、有一个initialized原子变量,保证初始化内容只会执行一次
2、接着ServiceLoader<InitFunc> loader = ServiceLoader.load(InitFunc.class); 这行代码就是通过JDK自带的SDK自带的SPI机制获取InitFunc的实现类了,对SPI机制不熟悉的可以自查资料了解下;
这里默认自带了4种初始化内容
- CommandCenterInitFunc:命令中心初始化
- FileDataSourceInit:文件数据源初始化,要这个有效的话,要引入sentinel-demo-dynamic-file-rule模块;并在META-INF/services中加入该类,才可以初始化加载;功能就是把sentinel的规则变量写入到文件中。
- HeartbeatSenderInitFunc: 心跳发送初始化
- ParamFlowStatisticSlotCallbackInit :热点参数统计插槽初始话,通过StatisticSlotCallbackRegistry注册
3、接下来第一个循环就是要初始的Init进行排序,
4、第二个循环就排序的顺序加载初始化
这里我们先进入到CommandCenterInitFunc中;
六、进入CommandCenterInitFunc
image.png1、同样是通过SPI加载ComandCenter的实现类,这里用的是SimpleHttpCommandCenter,因为dashboard引入的sentinel-transport-simple-http模块,若是引入netty-http模块则是NettyHttpCommandCenter
2、然后执行beforeStart()和start()方法
七、进入SimpleHttpCommandCenter
先执行beforeStart方法
image.png1、通过CommandHandlerProvider的namedHandlers方法获取所有的CommandHandler,见第八步
2、并把获取的ComandHandler注册到handlerMap中
接下来执行start方法
1、获取机器的核数
2、创建一个bizExecutor线程池
3、创建一个serverInitTask线程任务
4、放入到executor线程池(单个线程)中执行,在个线程中会把HttpEventTask任务放到bizExecutor线程池中的线程处理
八、进入CommandHandlerProvider
这里同样通过SPI机制获取实现了CommandHandler的类
image.png可以发现实现ComandHandler有这么多。
image.png
1、在for循环中把获取注释的CommandMapping注解的类,并放入Map<String, CommandHandler>这个map中,方便下次直接获取。
回到SimpleHttpCommandCenter类的beforeStart方法中。
总结
1、sentinel在首次资源访问的的过程中SPI机制加载初始化的内容,后续资源进来了不用在加载一遍。
2、SPI机制sentinel用的很多,但是这个JDK在的SPI加载有个缺点,就是全量加载,很多没有用的功能也加载进来了;可以参考Dubbo的ExtensionLoader进行懒加载。
3、可以说sentinel首次加载的过程就是InitFunc加载的过程。
4、这里初始化只分析了CommandCenterInitFunc;至于其它几个:FileDataSourceInitsentinel默认没有用到,
ParamFlowStatisticSlotCallbackInit热点参数的,还在实践中,
HeartbeatSenderInitFunc这个就是用来发送心跳的。
以上内容,若有不当之处,谢谢指正
网友评论