sentinel入门

sentinel入门

  • 一、下载安装
  • 二、配置
  • 三、使用
          • 一、流控规则
          • 二、降级规则
          • 三、热点规则
          • 四、系统规则
          • 五、授权规则
          • 六、自定义异常结果
          • 七、@SentinelResource
          • 八、整合OpenFeign
          • 九、配置持久化

一、下载安装

下载地址
https://github.com/alibaba/Sentinel/releases
sentinel入门_第1张图片
下载下来直接执行
java -jar sentinel-dashboard-1.8.3.jar 即可运行,默认端口为 8080
打开网站 http://localhost:8080
用户:sentinel
密码:sentinel
下载安装完成。

二、配置

一、首先在 pom.xml 中添加包


<dependency>
   <groupId>com.alibaba.cloudgroupId>
   <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
   <version>2.2.1.RELEASEversion>
dependency>

二、在 application.yml 置文件中添加 sentinel 部分

server:
  port: 9001

spring:
  application:
    #服务名
    name: openfeign9001
  cloud:
    #注册中心
    nacos:
      discovery:
        ###服务注册地址
        server-addr: 127.0.0.1:8848
        #server-addr: 127.0.0.1:8848
    #熔断限流
    sentinel:
      transport:
        port: 8719  #默认端口8719,如果被占用从8719开始+1直到找到未被占用的端口
        dashboard: localhost:8080 #安装的sentinel地址

三、使用

创建一个 coltroller 类

@RestController
@Slf4j
public class GetUserController {

    @GetMapping("/getUserName")
    public  String getUserName(){

        log.info("getUserName11");

        return "getUserName";
    }
 }

启动项目,执行请求 http://localhost:9001/getUserName
刷新sentinel页面即可看到请求,必须执行一次接口情况才能监控得到
sentinel入门_第2张图片
下边开始介绍是如何如何熔断降级的

一、流控规则

sentinel入门_第3张图片
QPS:表示发起请求
线程数:表示允许的线程
单机阈值:表示每秒钟允许请求或者线程的个数
流控模式:
(1)直接:根据自己这个方法的限制控制自己方法是否能被调用
(2)关联:关联资源的接口如果超过控制,则资源名的资源被限制访问
如下图所示,当 /getUserName1 接口每秒钟请求数超过一个,则 /getUserName接口无法访问。
sentinel入门_第4张图片
(3)链路:链路流控模式指的是,当从某个接口过来的资源达到限流条件时,开启限流。它的功能有点类似于针对来源配置项,区别在于:针对来源是针对上级微服务,而链路流控是针对上级接口,也就是说它的粒度更细。
例如:创建一个controller,有两个方法,调取同一个service,只控制其中的一个方法的调用
注意:sentinel 1.70以后使用链路规则需要
添加maven包

		<!--sentinel 1.70以后使用链路规则需要-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-web-servlet</artifactId>
            <version>1.7.0</version>
        </dependency>

需要添加配置类

@Configuration
public class FilterContextConfig {


    /**
     * sentinel链路模式需要
     * @return
     */
    @Bean
    public FilterRegistrationBean sentinelFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new CommonFilter());
        registration.addUrlPatterns("/*");
        // 入口资源关闭聚合
        registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
        registration.setName("sentinelFilter");
        registration.setOrder(1);
        return registration;
    }
}

controller:

@RestController
public class TestController {
    @GetMapping("/getC1")
    public String getC1(){

        return testService.getC();
    }

    @GetMapping("/getC2")
    public String getC2(){

        return testService.getC();
    }
}

service:

@Service
public class TestService {


    @SentinelResource(value = "getC") //sentinel资源名
    public String getC(){
        return "TestServiceGetC";
    }
}

启动服务,请求接口,刷新sentinel
sentinel入门_第5张图片
添加链路流控规则
sentinel入门_第6张图片
这样,在请求 /getC1 的时候每秒不能超过一次,否则就失败,请求 /getC2 则不受限制。

流控效果:
(1)快速失败:当求情达到阈值时,直接抛出异常。
(2)Warm UP:预热/冷启动(默认冷加载因子为 3 )
在设置的 “预热时长” 内,单机阈值从设置的三分之一开始慢慢达到所设置的阈值。
sentinel入门_第7张图片
如图所示表示访问接口 “/getA” 资源的时候,最开始的访问次数阈值为 15/3=5,表示一开始访问接口每秒不能超过 5 个请求,“预热时长”为 3 秒,表示三秒之后接口阈值为 15,在这三秒的时间内阈值从 5 匀速增加到 15。当请求量下降之后,接口阈值又会回到 5 。
(3)排队等待:严格的控制请求之间的时间间隔,让请求以均匀的速度通过,对应的是漏斗算法。
这种方式主要用于处理间隔性突发的流量,避免某一秒有大量的请求,拒绝了大部分的请求,下一秒又处于空闲状态浪费资源。加上排队等待后,第一秒巨量的请求可以进行排队,等下一秒空闲的时候处理。
超时时间:排队等待的时间,超过这个时间之后请求失败。
sentinel入门_第8张图片
上图所示,接口每秒处理五个请求,每五分之一秒到队列中接收一个请求,队列中的请求排队时间如果超过设置的3000毫秒(3秒)钟时间的话,请求就会失败。

二、降级规则

三种熔断策略如果生效都需要达到QPS(每秒请求数)达到设置的最小请求数。
最小请求数:每秒请求接口的个数。
(1)慢调用比例
sentinel入门_第9张图片
RT:平均响应时间。
当每秒请求的“平均响应时间"超过阈值 的比例超过 “比例阈值” ,且 “最小请求数” 超过 5,
则发生服务熔断,“熔断时长” 过后,接口可以访问。

(2)异常比例
sentinel入门_第10张图片
接口出现异常的比例超过 “比例阈值” 且 每秒“最小请求数” 超过 5 ,服务发生熔断。
(3)异常数
sentinel入门_第11张图片
当资源 一分钟 内的异常数超过阈值,且QPS超过 5 ,接口发生熔断。需要注意的是 熔断时长 需要大于等于 60s。

三、热点规则

热点规则比流控规则是一种更细粒度的流控规则,它允许将规则具体到参数上。
sentinel入门_第12张图片

     /**
     * 热点限流
     * @return
     */
    @GetMapping("/getH")
    @SentinelResource(value = "getH" ,blockHandler = "blo_getH")
    public String getH(@RequestParam(value = "aa",required = false)String aa,
                       @RequestParam(value = "bb",required = false)String bb){


        return "getH"+aa;
    }

    public String blo_getH(String aa ,String bb,BlockException exception){
        return "blo_getH"+aa;
    }

如上图配置完之后,当请求中有第一个参数则有QPS限制,没有第一个参数则没有限制。

四、系统规则

Sentinel系统自适应限流从整体维度对应入口流量进行控制,结合应用的Load、cup使用率、总体平均RT、入口QPS和并发线数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统规则支持以下的模式:

1、Load 自适应(仅对Linux/Unix-like机器生效):系统的load1作为启发指标、进行自适应系统保护。当系统load1超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR阶段)。系统容量由系统的maxQps*minRt估算得出。设定参考值一般事CPU cores * 2.5.

2、CPU usage:当系统CPU使用率超过阈值即触发系统保护(取值范围0.0-1.0),比较灵活。

3、平均RT:当单台机器上所有入口流量的平均RT达到阈值即触发系统保护,单位是毫秒。

4、并发线程数:当单台机器上的所有入口流量的并发线程数达到阈值即触发系统保护。

5、入口QPS:当单台机器上的所有入口流量的QPS达到阈值即触发系统保护。
sentinel入门_第13张图片
系统规则使用的情况比较少,它是对整个系统限制(起到总控作用),比较危险,一般不建议用。

五、授权规则

授权规则可以对调用方的来源做控制,有白名单和黑名单两种方式。
1、白名单:来源(origin)在白名单内的调用者允许访问
2、黑名单:来源(origin)在黑名单内的调用者不允许访问
sentinel入门_第14张图片
我们允许请求从gateway到order-service,不允许浏览器访问order-service,那么白名单中就要填写网关的来源名称(origin)。

如何获取origin:通过RequestOriginParser这个接口的parseOrigin来获取请求的来源

public interface RequestOriginParser {
    /**
     * 从请求request对象中获取origin,获取方式自定义
     */
    String parseOrigin(HttpServletRequest request);
}

这个方法的作用就是从request对象中,获取请求者的origin值并返回。

默认情况下,sentinel不管请求者从哪里来,返回值永远是default,也就是说一切请求的来源都被认为是一样的值default。

因此,我们需要自定义这个接口的实现,让不同的请求,返回不同的origin。

示例-实现RequestOriginParser返回origin

在服务调用者中添加如下代码:

@Component
public class HeaderOriginParser implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest request) {
        // 1.获取请求头
        String origin = request.getHeader("origin");
        // 2.非空判断
        if (StringUtils.isEmpty(origin)) {
            origin = "blank";
        }
        return origin;
    }
}

给网关添加请求头

既然获取请求origin的方式是从reques-header中获取origin值,我们必须让所有从gateway路由到微服务的请求都带上origin头。

这个需要利用GatewayFilter来实现,AddRequestHeaderGatewayFilter。

修改gateway服务中的application.yml,添加一个defaultFilter:

spring:
  cloud:
    gateway:
      default-filters:
        - AddRequestHeader=origin,gateway
      routes:
       # ...

这样,从gateway路由的所有请求都会带上origin头,值为gateway。而从其它地方到达微服务的请求则没有这个头。

配置授权规则

放行origin值为gateway的请求。
sentinel入门_第15张图片
现在,我们直接跳过网关,访问服务:

sentinel入门_第16张图片
通过网关访问:

sentinel入门_第17张图片

六、自定义异常结果

默认情况下,发生限流、降级、授权拦截时,都会抛出异常到调用方。异常结果都是flow
limmiting(限流)。这样不够友好,无法得知是限流还是降级还是授权拦截。

异常类型

如果要自定义异常时的返回结果,需要实现BlockExceptionHandler接口:

public interface BlockExceptionHandler {
    /**
     * 处理请求被限流、降级、授权拦截时抛出的异常:BlockException
     */
    void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception;
}

这个方法有三个参数:

HttpServletRequest request:request对象
HttpServletResponse response:response对象
BlockException e:被sentinel拦截时抛出的异常

这里的BlockException包含多个不同的子类:

异常 说明
FlowException 限流异常
ParamFlowException 热点参数限流的异常
DegradeException 降级异常
AuthorityException 授权规则异常
SystemBlockException 系统规则异常

自定义异常处理

在服务调用方自定义Sentinel异常处理类:

@Component
public class SentinelExceptionHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        String msg = "未知异常";
        int status = 429;

        if (e instanceof FlowException) {
            msg = "请求被限流了";
        } else if (e instanceof ParamFlowException) {
            msg = "请求被热点参数限流";
        } else if (e instanceof DegradeException) {
            msg = "请求被降级了";
        } else if (e instanceof AuthorityException) {
            msg = "没有权限访问";
            status = 401;
        }

        response.setContentType("application/json;charset=utf-8");
        response.setStatus(status);
        response.getWriter().println("{\"msg\": " + msg + ", \"status\": " + status + "}");
    }
}

七、@SentinelResource

@SentinelResource是sentinel必须会使用的注解,其主要有以下作用

一、作为资源名

在使用流控的时候资源可以通过两种方式加入到控制台,一种是通过url,一种是通过注解。

    @GetMapping("/getI")
    @SentinelResource(value = "getI")
    public String getI(@RequestParam(value = "aa",required = false)String aa){

        return "getI"+aa;
    }

对应下图中的资源名
sentinel入门_第18张图片
通过注解添加的资源名(不带斜杠)比直接url的资源名使用更方便

二、配置兜底的方法
@SentinelResource中的 blockHandler 可以指定兜底的方法

@GetMapping("/getI")
    @SentinelResource(value = "getI" ,blockHandler = "blo_getI")
    public String getI(@RequestParam(value = "aa",required = false)String aa){

        return "getI"+aa;
    }

    /**
     * getI 的兜底的方法
     * @param aa
     * @param exception
     * @return
     */
    public String blo_getI(String aa ,BlockException exception){

        return "blo_getI:"+aa+"异常信息:"+exception.getMessage();
    }

其中兜底方法的 BlockException 是必须的参数,要不然会不起作用。

@SentinelResource中的blockHandlerClass 可以指定兜底的方法类配合blockHandler一起使用

@RestController
@Slf4j
public class TestController {
    /**
     * blockHandlerClass:限流兜底的类
     * blockHandler:限流兜底的类的方法
     * @return
     */
    @GetMapping("/getG")
    @SentinelResource(value = "getG",blockHandlerClass = TestBlockHand.class,blockHandler = "blo_getG")
    public String getG(){

        return "getG";
    }
}

另一个类中

@Slf4j
public class TestBlockHand {
    /**
     * 注意:这个兜底的方法必须是 static 静态的方法
     * @param exception
     * @return
     */
    public static String blo_getG(BlockException exception){

        log.info("我是限流兜底的方法loc_getG");
        return "loc_getG";
    }
}

另一个兜底的方法必须是 static 静态方法

三、异常兜底方法
通过@SentinelResource中的fallback 配置接口异常的兜底方法。

@GetMapping("/getJ")
    @SentinelResource(value = "getJ" ,fallback = "getJ_back")
    public String getJ(@RequestParam(value = "aa",required = false)String aa){
        int i = 1/0;
        return "getJ"+aa;
    }

    /**
     * getJ接口异常的兜底方法
     * @param aa
     * @return
     */
    public String getJ_back(String aa){
        return "getJ接口异常,入参:"+aa;
    }

因为 getJ 发放中存在运行异常,所以请求接口会进入异常兜底方法 getJ_back 中
sentinel入门_第19张图片
四、exceptionsToIgnore:忽略哪些异常类

@GetMapping("/getK")
    @SentinelResource(value = "getK" ,fallback = "getK_back" ,
            exceptionsToIgnore = {IllegalArgumentException.class})
    public String getK(@RequestParam(value = "aa",required = false)String aa){

        if(aa == null){
            throw new IllegalArgumentException();
        }else{
            int i=1/0;
        }
        return "getK"+aa;
    }


    public String getK_back(String aa){
        return "getK接口异常,入参:"+aa;
    }

如果 getK 的入参 aa 为空,则不会进入 getK_back 方法。

八、整合OpenFeign

需要在配置文件中添加:

#激活 sentinel 对 feign 的支持,要不然 @FeignClient中的 fallback 不起作用
feign:
  sentinel:
    enabled: true
九、配置持久化

sentinel的限流规则配置之后,一旦微服务重启,则此微服务配置的规则都去删除,所以需要配置持久化,sentinel通过nacos配置管理来实现持久化功能。

pom.xml 中添加

        
        <dependency>
            <groupId>com.alibaba.cspgroupId>
            <artifactId>sentinel-datasource-nacosartifactId>
            <version>1.8.3version>
        dependency>

application配置文件中的 sentinel 添加 datasource

spring:
  application:
    #服务名
    name: openfeign9001


  cloud:
    #注册中心
    nacos:
      discovery:
        ###服务注册地址
        server-addr: 127.0.0.1:8848
        #server-addr: 127.0.0.1:8848
    #熔断限流
    sentinel:
      transport:
        port: 8719
        dashboard: localhost:8080
      #sentinel 持久化到 nacos
      datasource:
        ds1:    #数据源1
          nacos:
            server-addr=localhost: 8848  #nacos 地址
            data-id: ${spring.application.name}  #配置文件id(一般使用本服务名)
            group-id: DEFAULT_GROUP      #默认 分组
            data-type: json              #数据类型 json
            rule-type: flow

测试接口

/**
     * sentinel持久化测试
     * @return
     */
    @GetMapping("/persistenceTest")
    @SentinelResource(value = "persistenceTest",blockHandler = "blo_persistenceTest")
    public  String persistenceTest(){

        log.info("persistenceTest");

        return "persistenceTest";
    }


    public  String blo_persistenceTest(BlockException exception){

        log.info("blo_persistenceTest");

        return "blo_persistenceTest";
    }

在nacons的配置管理中添加
sentinel入门_第20张图片

[
    {
        "resource": "persistenceTest",
        "limitApp": "default",
        "grade": 1,
        "count": 1,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]

resource:资源名称
limitApp:来源应用
grade:阈值类型:0表示线程数;1表示QPS
count:单机阈值
strategy:流控模式:0表示直接;1表示关联;2表示链路
controlBehavior:流控效果:0表示快速失败;1表示Warm Up;2表示排队等待
clusterMode:是否集群

启动 openfeign9001 微服务,请求 persistenceTest 接口,刷新sentinel控制台,流控规则就自动生成了
sentinel入门_第21张图片

你可能感兴趣的:(微服务,java)