SpringCloudAlibaba之Sentinel哨兵

写在前面

本文参照Spring官方文档,并实现了代码,在此做下笔记;

随着微服务的流行,服务调用的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件,主要以“流量”为切入点,从流量控制、断路和负载保护等多个维度来保障服务可靠性。

哨兵拥有以下特性:

  • 控制突发的流量,使其处于系统容量可接受的范围内,消息削峰填谷,集群流量控制、实时熔断下游不可用应用等。
  • 全面实时监控:Sentinel 提供实时监控能力。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500台以下规模的集群的汇总运行情况。
  • 广泛的开源生态系统:Sentinel 提供了开箱即用的模块,可以很容易地与其他开源框架/库集成,比如 Spring Cloud、Dubbo 和 gRPC,您只需要引入相应的依赖项并进行一些简单的配置。
  • SPI 拓展:Sentinel 提供了易用和可靠的 SPI 拓展接口。您可以使用 SPI 拓展快速定制逻辑,例如,您可以定义自己的规则管理,或者适应动态数据源等。
    这里附上一张官网总结的特性图:
    SpringCloudAlibaba之Sentinel哨兵_第1张图片

Sentinel 入门

新建 sentinel-app 子模块。如果想要在项目中使用 Sentinel ,需要导入如下依赖:

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

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-webartifactId>
dependency>

下面是一个关于如何使用 Sentinel 的用例:

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(ServiceApplication.class, args);
    }

}

@RestController
public class TestController {

    @GetMapping(value = "/hello")
    @SentinelResource("hello")
    public String hello() {
        return "Hello Sentinel";
    }

}

@SentinelResource 注解是用于标识资源是否受到速率限制或降级。在上面的用例中,注解中的 ‘hello’ 属性值指的是资源名。

资源 是 Sentinel 中的核心概念之一。最常用的资源是我们代码中的 Java 方法。当然,也可以更灵活的定义资源,例如,将需要控制流量的代码用 Sentinel API SphU.entry("helloWorld")entry.exit() 包围起来。

    @GetMapping("/helloWorld")
    public String helloWorld(){
        try(Entry entry = SphU.entry("helloWorld")){
            //被保护的业务逻辑
            return "helloWorld";
        }catch (BlockException exception){
            //资源访问阻止,被限流或被降级
            System.out.println("blocked!");
            return "blocked!";
        }
    }

Sentinel Dashboard

在我们运行上面的测试用例之前,先让我们来搭建好 Sentinel Dashboard。

Sentinel Dashboard 是一种轻量级控制台,它提供机器发现、单服务器资源监视、集群资源数据概览以及规则管理等功能。要使用这些特性,您需要完成以下几个步骤:

集群统计只支持节点少于 500 个的集群,延迟大约 1 到 2 秒。

  1. 下载稳定的 dashboard JAR 包;

  2. 启动:java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

    访问地址 http://:8080

SpringCloudAlibaba之Sentinel哨兵_第2张图片
3. 客户端访问 dashboard:在上面的测试用例中添加如下配置:

spring:
  cloud:
    sentinel:
      transport:
        port: 8720
        dashboard: localhost:8080

使用如上的配置,你需要在程序启动后,手动访问用例的 http://192.168.3.18:18085/hello 地址,才能看如下界面:

SpringCloudAlibaba之Sentinel哨兵_第3张图片

不过,你也可以通过新增 eager 配置,在启动后就能初始化:

spring:
  application:
    name: sentinel-app
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080
        heartbeat-interval-ms: 10000
        port: 8720
      eager: true

现在,启动我们的应用程序,可以尝试不断地访问接口地址,来观察 Dashboard 实时监控栏的变化!


OpenFeign 支持

实现 openFeign 支持,项目需要做比较大的改动;

  1. 引入依赖:

    		<dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-openfeignartifactId>
            dependency>
    

    不过由于这个依赖是由 spring-cloud-dependencies 所管理的,所以我们需要先在顶层模块下加入如下:

    	<dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>com.alibaba.cloudgroupId>
                    <artifactId>spring-cloud-alibaba-dependenciesartifactId>
                    <version>2.1.0.RELEASEversion>
                    <type>pomtype>
                    <scope>importscope>
                dependency>
                <dependency>
                    <groupId>org.springframework.cloudgroupId>
                    <artifactId>spring-cloud-dependenciesartifactId>
                    <version>Greenwich.SR2version>
                    <type>pomtype>
                    <scope>importscope>
                dependency>
            dependencies>
        dependencyManagement>
    
  2. 引入 nacos-discovery 来支持远程调用:

    		>
                >com.alibaba.cloud>
                >spring-cloud-starter-alibaba-nacos-discovery>
            >
    
  3. 修改启动类,使其支持 nacos-discovery 以及 feign:

    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableFeignClients
    public class Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    }
    
  4. 添加 openFeign 测试用例:

    @FeignClient(name = "provider-app", fallback = EchoServiceFallback.class, configuration = FeignConfiguration.class)
    public interface EchoService {
    
        @GetMapping("/echo/{str}")
        String echo(@PathVariable("str") String str);
    }
    
    class FeignConfiguration{
        @Bean
        public EchoServiceFallback echoServiceFallback(){
            return new EchoServiceFallback();
        }
    }
    
    class EchoServiceFallback implements EchoService{
    
        @Override
        public String echo(String str) {
            return "echo fallback";
        }
    }
    
  5. 修改当前的测试用例,使其使用 feign 的测试用例:

    @RestController
    public class TestController {
    
        @Resource
        private EchoService echoService;
    
        @GetMapping("/hello")
        @SentinelResource("hello")
        public String hello(){
            return "Hello Sentinel";
        }
    
        @GetMapping("/echo/{str}")
        public String echo(@PathVariable String str){
            return echoService.echo(str);
        }
    }
    
  6. 修改配置文件:

    server:
      port: 18085
    spring:
      application:
        name: sentinel-app
      cloud:
        sentinel:
          transport:
            dashboard: localhost:8080
            heartbeat-interval-ms: 10000
            port: 8720
          eager: true
        nacos:
          discovery:
            server-addr: 127.0.0.1:8848
            network-interface: eth9
            namespace: ecbbf883-5744-42e3-b448-09aabee90d7f
    feign:
      sentinel:
        enabled: true
    management:
      endpoints:
        web:
          exposure:
            include: nacos-discovery
    

现在,启动 provider-app 子模块(服务提供者)以及当前的 sentinel-app 项目;查看 Nacos 控制台,两个服务都注册成功。我们可以尝试不断访问上面的测试用例地址:http://192.168.3.18:18085/echo/hello,然后观察 Sentinel Dashboard 的实时监控一栏的变化。


RestTemplate 支持

Sentinel 也支持保护 RestTemplate 的服务调用。我们只需要在构造 RestTemplate bean 时添加 @SentinelRestTemplate 注解:

@Bean
@SentinelRestTemplate(blockHandler = "handleException", blockHandlerClass = ExceptionUtil.class)
public RestTemplate restTemplate() {
    return new RestTemplate();
}

该注解的属性支持流量控制(blockHandlerblockHandlerClass ) 和断路(fallbackfallbackClass )。并且,这个 blockHandler 或者 fallback 指定的方法必须是 blockHandlerClass 或者 fallbackClass 的静态方法。

方法的入参和返回应该和 org.springframework.http.client.ClientHttpRequestInterceptor#interceptor 一样,但是,可以多一个 BlockException 来通过 Sentinel 捕获异常。所以,handleException 方法如下:

public class ExceptionUtil {
    public static ClientHttpResponse handleException(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException exception) throws IOException {
        return execution.execute(request, body);
    }
}

现在,让我们来完善这个测试用例。除了上面的两处变动外,我们需要在 TestController 类中做些改动来测试。TestController 新增如下代码:

	@Autowired
    private LoadBalancerClient loadBalancerClient;
    @Autowired
    private RestTemplate restTemplate;
    @Value("${spring.application.name}")
    private String appName;

	@GetMapping("/echo/app-name")
    public String echoAppName(){
        ServiceInstance serviceInstance = loadBalancerClient.choose("provider-app");
        String path = String.format("http://%s:%s/echo/%s", serviceInstance.getHost(), serviceInstance.getPort(), appName);
        System.out.println("request path: " + path);
        return restTemplate.getForObject(path, String.class);
    }

重启应用程序,访问上面的接口地址,观察 dashboard 实时监控栏变化!(关于流控的具体介绍,我打算重新写一篇博客来介绍)。

Sentinel 也提供了对 Zuul 以及 Gateway 的支持,这里就不再介绍了!

Sentinel 端点

Sentinel 提供了一个 /sentinel 端点,该端点暴露的主要内容如下:

  1. appName: 应用程序名;
  2. logDir: 日志目录;
  3. logUsePid: 日志名是否使用 Pid;
  4. blockPage: sentinel 阻塞后直接跳转的页面;
  5. metricsFileSize: 度量的文件大小;
  6. metricsFileCharset: 度量的文件编码;
  7. totalMetricsFileCount: 度量文件的总文件计数;
  8. consoleServer: 哨兵的仪表盘地址;
  9. clientIp: client ip;
  10. heartbeatIntervalMs: 客户端与仪表盘的心跳间隔;
  11. clientPort: 客户端需要公开端口以与仪表板交互;
  12. coldFactor: cold factor;
  13. filter: CommonFilter related properties, such as order, urlPatterns and enable;
  14. datasource: datasource configuration info by client;
  15. rules: the rule that the client takes effect internally contains flowRules, degradeRules, systemRules, authorityRule, paramFlowRule;

末尾有几个内容不太懂,我们都将在后续一一弄明白。注意,端点都需要在配置文件中进行暴露以后,才可以访问。

Sentinel 配置

ApplicationContext 中存在下列相应的 bean 时,会产生相应的行为:

  1. UrlCleaner : 处理 url,对一些路径变量进行统一处理,例如 collect_item_relation--10200012121-.html 将被转换为 collect_item_relation.html

  2. UrlBlockHandler : 在 URL 被 sentinel 阻塞时,应执行的处理程序;

  3. RequestOriginParser : 解析给定请求的来源;

上面的 bean 都将通过 WebCallbackManager 统一管理调用。

Sentinel 的配置可以查看相应的文档或者 SentinelProperties 类。


我与风来

认认真真学习,做思想的产出者,而不是文字的搬运工。
SpringCloudAlibaba之Sentinel哨兵_第4张图片
但行善事,莫问前程。

你可能感兴趣的:(SpringCloudAlibaba之Sentinel哨兵)