九、SpringCloud Alibaba Sentinel

CY 2019年03月23日 261次浏览

Sentinel类似于之前的Hystrix,它的优点是有自己的监控平台,可以用Web界面来更加细粒度化的配置。

使用Sentinel

SentinelNacos一样需要在Release那里去下载,下载完成后直接使用java -jar来运行就好了,默认的端口是8080,运行后默认的登录账号和密码都是sentinel

然后在项目中导入下面坐标:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

配置:

server:
  port: 8001
spring:
  application:
    name: sentinel-service
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080
        # 默认使用8719端口,如果被占用则会自动+1扫描
        port: 8719

management:
  endpoints:
    web:
      exposure:
        include: "*"

启动类略,写两个接口准备测试:

@RestController
public class EchoController {

    @Value("${server.port}")
    private String port;

    @GetMapping(value = "/limitA")
    public String limitA() {
        return port + ": Hello Sentinel! A";
    }

    @GetMapping(value = "/limitB")
    public String limitB() {
        return port + ": Hello Sentinel! B";
    }
}

访问上面的两个接口,即可在Sentinel控制面板中显示出来当前微服务的信息。

流量控制

官方解释

QPS-直接-快速失败

QPS-直接-快速失败

疯狂点击接口limitA,发现页面上会出现:Blocked by Sentinel (flow limiting),这就意味着一秒钟只能接收1次请求已经生效了。

线程数-直接

接口A修改为下面的样子。

@GetMapping(value = "/limitA")
public String limitA() {
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return port + ": Hello Sentinel! A";
}

修改流控规则到线程数-直接,阈值为1,然后进行测试。

然后疯狂的访问接口,这个时候也会显示Blocked by Sentinel (flow limiting),它和QPS的区别:

QPS限制的是请求的数量,请求超过数量就不允许请求进入了。

线程数是所有的请求都可以进入,只有当规定阈值个线程已经处理不过来了,才会出现流控提示。

流控模式-关联

举个具体使用的例子,比如说支付接口出现了问题,那么就去限流下订单的接口。也就是说支付接口和下订单接口是关联关系。

image.png

疯狂的访问/limitB接口,然后发现/limitA接口不能用了。

流控效果-Warm Up(预热)

预热是防止接口被突如其来的大量访问,某个接口一直处于无人问津的状态,突然间就有了特别大的访问量,所以需要提供预热的效果。

image.png

阈值为10,预热时长为5,系统的coldFactor默认为3,意思就是还没有到预热时长的时候针对突如其来的访问只能让3个请求访问成功(10 / 3),过了预热时长后就会到达正常的阈值。

流控效果-排队等待

image.png

设置QPS为1,然后在QPS达到规定的阈值之后会让后面的请求排队等待,除非后面的请求等的不耐烦了(超过了超时时间),页面上就会显示限流提示信息。

测试的时候可以通过打日志的方式:

log.info(Thread.currentThread().getName() + ": 进入了...");
2020-03-22 16:30:25.492  INFO 19344 --- [nio-8001-exec-2] com.cy.controller.EchoController         : http-nio-8001-exec-2: 进入了...
2020-03-22 16:30:51.791  INFO 19344 --- [nio-8001-exec-4] com.cy.controller.EchoController         : http-nio-8001-exec-4: 进入了...
2020-03-22 16:30:52.791  INFO 19344 --- [nio-8001-exec-5] com.cy.controller.EchoController         : http-nio-8001-exec-5: 进入了...
2020-03-22 16:30:53.791  INFO 19344 --- [nio-8001-exec-6] com.cy.controller.EchoController         : http-nio-8001-exec-6: 进入了...
2020-03-22 16:30:54.791  INFO 19344 --- [nio-8001-exec-7] com.cy.controller.EchoController         : http-nio-8001-exec-7: 进入了...
2020-03-22 16:30:55.791  INFO 19344 --- [nio-8001-exec-8] com.cy.controller.EchoController         : http-nio-8001-exec-8: 进入了...
2020-03-22 16:30:56.792  INFO 19344 --- [nio-8001-exec-9] com.cy.controller.EchoController         : http-nio-8001-exec-9: 进入了...

降级规则

Sentinel里面是没有半开(Half Open)状态的。

RT(平均响应时间)

image.png

当1秒之内有5次请求,且5次请求的平均响应时间超过了设定的RT值(上图是200毫秒),接口会被限流,等到到达规定的时间窗口1S,就会恢复正常的调用。

默认的RT上限是:4900ms,超过4900ms也算作4900ms

异常比例

异常比例,就不截图了。

还是在1秒之内5次请求,如果这5次请求的异常比例超过了设定的值,将会在规定的时间窗口期内接口无法使用,接口会提示Blocked by Sentinel (flow limiting)

时间窗口的时间过了之后就会提示异常信息了,而不是Blocked by Sentinel (flow limiting)

这是因为Blocked by Sentinel (flow limiting)这个提示只有在降级的时候才会被显示。

异常数

异常数是按照分钟统计的,1分钟之内的异常数量超过了设定的数量,就会进入降级。

热点规则

举个比较形象的例子,比如说在微博中某个明星出轨了,基本上微博就会炸掉,热点规则就可以避免这个问题。

他是通过请求的参数进行限流的,当某个参数使用了相同的值进行了大量的访问,会被限流。

@GetMapping(value = "/limitC")
@SentinelResource(value = "limitC", blockHandler = "fallback")
public String limitC(String key1, String key2) {
    return port + ": Hello Sentinel! " + key1 + " ==> " + key2;
}

public String fallback(String key1, String key2, BlockException e) {
    return key1 + " ==> " + key2 + "已经被限流了..." + e.getMessage();
}

上面代码中使用了@SentinelResource注解,该注解中的blockHandler参数规定了降级方法。

image.png

这个配置的意思是,当第一个参数的单机阈值为1的时候进行降级,降级持续时长为1秒。

热点规则只能使用资源名(@SentinelResource中的value值)来进行限流,如果不使用blockHandler,会抛出异常,所以热点规则要尽量添加blockHandler

添加参数例外项

也不需要解释太多的东西,一张图片就懂了。

image.png

当参数值为明星的时候,限流阈值为100。

需要注意blockHandler只能作为与Sentinel控制台配置不一致的时候使用的降级方法,不能作为程序异常时候的降级方法,应该添加fallback参数,在降级方法中可以注入异常类

系统规则

相当于在整个系统上添加了规则,作用在全局的规则,更加粗粒度。

只支持5中模式:

image.png

降级方法解耦

写一个针对某个类的专门的降级类,里面的降级方法首先必须要是静态的,其次,必须要和它对应的降级方法的参数保持一致,并且加入BlockException参数,否则将无法使用降级方法。

public class GlobalHandler {

    public static String handler(String key1, String key2, BlockException e) {
        return "全局的降级方法..." + e.getMessage();
    }
}
@SentinelResource(value = "limitC", 
                  blockHandlerClass = GlobalHandler.class, 
                  blockHandler = "handler")

其他注意事项

如果按照资源名称(@SentinelResource注解中的value)进行限流,则会使用注解中的降级方法,如果按照URI进行限流,则会使用系统默认的降级方法。

如果@SentinelResource注解中加入了fallback属性,则程序出现异常了就会走fallback

如果@SentinelResource注解中加入了blockHandler属性,则违反了Sentinel规则后走handler

如果只配置fallback,不配置blockHandler则会默认使用Sentinel的降级信息。

如果只配置blockHandler,不配置fallback并不会走程序异常时的降级方法。

可以使用exceptionsToIgnore来规定某个异常不要被fallback进行处理。

OpenFeign使用Sentinel

正常搭建起来一个OpenFeign项目,在项目中加入Sentinel的坐标,然后配置文件中添加:

feign:
  sentinel:
    enabled: true

OpenFeign使用Hystrix的流程一样,需要对原来的OpenFeign接口写一个实现类,然后在@FeignClient注解中加入fallback即可。

@FeignClient(value = "sentinel-service", 
             fallback = EchoServiceHandler.class)
...

Sentinel规则持久化

默认情况下Sentinel会在微服务重启的时候,配置的规则就会消失,因为默认情况下规则是保存在微服务的内存中的。

官方对于持久化的说明

【参考文档】持久化的5种方案