Sentinel源码解析之一次请求走进Sentinel

原创不易,转载请注明出处


前言

本篇开始,我们就正式进入Sentinel源码解析了,本篇主要是介绍下Sentinel与SpringMVC整合,发送批量请求去Sentinel控制台看看效果,最后我们就要揭秘一下Sentinel是怎样做到能够统计请求的。

1.整合Sentinel与Spring MVC

这里是用的springboot 然后导入spring-boot-starter-web 快速整合的Spring mvc
这里贴一下我的pom 引用

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-web-servlet</artifactId>
    <version>1.6.0</version>
</dependency>
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-transport-simple-http</artifactId>
    <version>1.6.0</version>
</dependency>

这里需要 sentinel与servlet的适配项目sentinel-web-servlet,这个项目主要是适配的, 然后还需要通信项目sentinel-transport-simple-http,这个主要是用来与控制台sentinel-dashboard 网络通信的。
接下来我们就得配置了

@Configuration
public class SentinelServletConfig implements WebMvcConfigurer {

    @Bean
    public FilterRegistrationBean sentinelFilterRegistration() {
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new CommonFilter());
        registration.addUrlPatterns("/*");
        registration.setName("sentinelFilter");
        registration.setOrder(1);

        //logger.info("Sentinel servlet CommonFilter registered");

        return registration;
    }
}

这里就是个配置类,然后注册一下CommonFilter 这个组件,想都不用想,sentinel就是通过这个filter 来进行流控的,这里配置所有的请求都走这个filter
然后就是再随便写个Controller。

@RestController()
@RequestMapping("/test")
public class TestController {
    @RequestMapping("/getName")
    public String getName(){
        System.out.println("getName");
        return null;
    }
}

2.批量请求看看效果

启动sentinel-dashboard 这个项目,它就是个springboot 项目,你可以随心所欲改动,我这里是8000 端口启动的。

在这里插入图片描述
账号密码都是sentinel,这可以在配置文件中配置。
在这里插入图片描述
登陆进去就是这个样子,现在只有它一个。
在这里插入图片描述
然后在启动上面整合的那个项目, 启动参数设置

-Dcsp.sentinel.dashboard.server=localhost:8000
-Dproject.name=consumer_app 

csp.sentinel.dashboard.server 这个参数就是 sentinel-dashboard 的地址,因为你那个项目启动的时候就要向这个dashboard 项目发送心跳啥的,然后dashboard 定时管你要Metric信息,不然它怎么实时展示。
project.name 项目名称,这个向dashboard 发送心跳的时候,会带上,用来区分项目的。
我们启动整合的那个项目。
启动完成后,再来看看sentinel 的dashboard, 发现还是没有变化,不是应该向sentinel发送心跳吗?其实,咱们项目启动并没有初始化这个sentinel,当我们发起请求的时候,经过这个CommonFilter 组件,就会进行sentinel的初始化,到时候我们再来看下 sentinel dashboard的效果。
先来发送一次请求,用什么工具随意,我这里用postman
ok,我这里发送完成了,看下效果,可以看到,这个dashboard 已经有我那个project了。
在这里插入图片描述
来组批量请求,看下sentinel dashboard 实时效果。我这里使用postman 发送1000次请求
在这里插入图片描述
在这里可以看到我某个请求的实时通过qps与拒绝qps ,响应时间。
在sentinel的世界中, 我们/test/getName 就是一个资源,你可以把一个接口看作一个资源。

3.走进Sentinel的Servlet适配项目

我们来看下 sentinel 与servlet适配项目的这个CommonFilter都干了些啥,简单看一下这个CommonFilter 的源码,在sentinel-web-servlet这个子项目中
在这里插入图片描述
首先是解析了一下 requset ,得到一个target,这里其实就是解析出来你的请求路径,接着就是使用UrlCleaner 把这个路径清理了一下,可以看下这个注释,就是这个意思,接着就是parseOrigin 方法来解析origin
在这里插入图片描述
这个originParser 是个null ,所以就不走了,这块其实就是解析源的,也就是这个请求的上层,你可以通过某种方式带过来,然后自己写个parser 再把这个源解析出来,这里我们就不看了。
接着就是

ContextUtil.enter(target, origin);
entry = SphU.entry(target, EntryType.IN);

这两行了我们这里重点 看下ContextUtil.enter(target, origin);,后面这个更重要,我们后面天天打交道。
在这里插入图片描述
判断name是不是sentinel_default_context ,很显然不是,执行trueEnter 方法
在这里插入图片描述
先是从contextHolder 中获取一个context ,这个contextHolder 就是个threadLocal,也就是一个线程一个context,如果没有的话,接着就是contextNameNodeMap 中获取 你这个name的 DefaultNode ,关于 DefaultNode 先不要管,如果node是null的话,这个map中缓存的是不是大于2000了,超过2000的话就往这个线程对应的threadLocal 设置一个空的context,下面就是加锁再来检查一遍,创建一个EntranceNode,你可以认为这个EntranceNode 是这个资源(就是你传过来的那个name)的起始 node, 然后根结点添加这个node为字节点,将name 对应node放入 map中缓存起来。创建context,然后将这个context 设置到treadLocal中。
好了,先解析到这里,其实这个name 你就可以认为一个资源,在servlet中就是/test/getName这种形式的,一个接口就是一个资源。一个资源对应一个EntranceNode,到后面还对应一个ClusterNode。

总结

本文主要是介绍了一下 sentinel 与我们springboot 的web 项目整合,其实什么web项目都是一样,配置一下CommonFilter,请求经过这个Filter ,sentinel就能发挥作用,然后就是批量请求了一下,感受了一下sentinel的实时监控功能,通过qps,拒绝qps,rt,最后就是看看这个CommonFilter 到底干了啥,这里并没有深入解析,而是简单看看,后面会有若干的篇章进行解析源码。

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页