SpringCloud整合Sentinel控制台不显示多层接口簇点链路

SpringCloud整合Sentinel控制台不显示多层接口簇点链路

leo 4422 2021-05-18

示例项目

示例项目 GitHub:https://github.com/leo1604270786/hello-sentinel

细节可以查看我的这篇文章 SpringCloud 整合 Sentinel 并连接 Nacos 改造后的控制台

pom.xml :

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>top.zysite</groupId>
    <artifactId>hello-sentinel</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <name>hello-sentinel</name>
    <description>Demo project for Spring Boot</description>
    <packaging>pom</packaging>

    <modules>
        <module>hello-sentinel-gateway</module>
        <module>hello-sentinel-normal</module>
    </modules>

    <properties>
        <spring-cloud.version>Hoxton.SR5</spring-cloud.version>
        <admin-starter-server.version>2.2.3</admin-starter-server.version>
        <spring-cloud-alibaba.version>2.2.0.RELEASE</spring-cloud-alibaba.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!--Spring Cloud 相关依赖-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--集成SpringBoot Admin监控-->
            <dependency>
                <groupId>de.codecentric</groupId>
                <artifactId>spring-boot-admin-starter-server</artifactId>
                <version>${admin-starter-server.version}</version>
            </dependency>

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

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


            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.75</version>
            </dependency>

        </dependencies>
    </dependencyManagement>

    <repositories>
        <repository>
            <id>spring</id>
            <url>https://maven.aliyun.com/repository/spring</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

原因

SpringCloud 整合 Sentinel 会通过SentinelWebAutoConfiguration自动配置类来对 Sentinel 进行配置,其中就包括注册 SentinelWebInterceptor 拦截器,来拦截 Web 请求,并且将 url 采集成资源,之后会在 sentinel-dashboard 中的簇点链路中展示,SentinelWebAutoConfiguration部分源码如下:

@Override
public void addInterceptors(InterceptorRegistry registry) {
    if (!sentinelWebInterceptorOptional.isPresent()) {
        return;
    }
    SentinelProperties.Filter filterConfig = properties.getFilter();
    registry.addInterceptor(sentinelWebInterceptorOptional.get())
        .order(filterConfig.getOrder())
        .addPathPatterns(filterConfig.getUrlPatterns());
    log.info(
        "[Sentinel Starter] register SentinelWebInterceptor with urlPatterns: {}.",
        filterConfig.getUrlPatterns());
}

在启动项目是可以看到下面这条日志:

2021-05-18 11:30:04.802  INFO 27797 --- [           main] c.a.c.s.SentinelWebAutoConfiguration     : [Sentinel Starter] register SentinelWebInterceptor with urlPatterns: [/*].

可以看到,注册的拦截器拦截的 url 模式串 为/*

也可以通过查看SentinelProperties.Filter类源码看到:

public static class Filter {

		/**
		 * SentinelWebInterceptor order, will be register to InterceptorRegistry.
		 */
		private int order = Ordered.HIGHEST_PRECEDENCE;

		/**
		 * URL pattern for SentinelWebInterceptor, default is /*.
		 */
		private List<String> urlPatterns = Arrays.asList("/*");

		/**
		 * Enable to instance
		 * {@link com.alibaba.csp.sentinel.adapter.spring.webmvc.SentinelWebInterceptor}.
		 */
		private boolean enabled = true;

		public int getOrder() {
			return this.order;
		}

		public void setOrder(int order) {
			this.order = order;
		}

		public List<String> getUrlPatterns() {
			return urlPatterns;
		}

		public void setUrlPatterns(List<String> urlPatterns) {
			this.urlPatterns = urlPatterns;
		}

		public boolean isEnabled() {
			return enabled;
		}

		public void setEnabled(boolean enabled) {
			this.enabled = enabled;
		}

	}

在没有添加@SentinelResource注解的情况下该模式串就会导致 Sentinel 只会拦截接口层级为 1 的 url。

如,下面只有/hello/sentinel(添加了注解)、param可以在 sentinel-dashboard 中的簇点链路中展示,而/hello/degrade不会展示,实时监控也看不到:

@RestController
public class HelloController {

    @SentinelResource(value = "hello", fallback = "sentinelFallback")
    @GetMapping("/hello/sentinel")
    public String sentinel(){
        return "hello sentinel";
    }

//    @SentinelResource(value = "degrade", fallback = "sentinelFallback")
    @GetMapping("/hello/degrade")
    public String degrade(){
        //测试降级
        if(new Random().nextInt() % 2 == 0) {
            return "hello degrade";
        } else {
            throw new RuntimeException("RuntimeException");
        }
    }

    @GetMapping("param")
    public String paramFlowRule(String param1, Integer param2) {
        return "paramFlowRule";
    }

    public String sentinelFallback() {
        return "hello fallback";
    }
}

注:以上源码都是在 spring-cloud-alibaba-dependencies 版本为 2.2.0.RELEASE 的情况下。

解决方案

添加配置

hello-sentinel-normalhello-sentinel-gateway模块的配置文件application.yml中添加以下配置:

spring:
  cloud:
    sentinel:
      filter:
        url-patterns: /**

重新启动即可在 sentinel-dashboard 中的簇点链路中展示所有 url。

修改版本

将 spring-cloud-alibaba-dependencies 版本改为 2.2.4.RELEASE

<spring-cloud-alibaba.version>2.2.4.RELEASE</spring-cloud-alibaba.version>

可以在 2.2.4.RELEASE 版本中,查看SentinelProperties.Filter类源码,url 模式串已经改为了/** ,不需要修改配置了:

public static class Filter {

		/**
		 * SentinelWebInterceptor order, will be register to InterceptorRegistry.
		 */
		private int order = Ordered.HIGHEST_PRECEDENCE;

		/**
		 * URL pattern for SentinelWebInterceptor, default is /**.
		 */
		private List<String> urlPatterns = Arrays.asList("/**");

		/**
		 * Enable to instance
		 * {@link com.alibaba.csp.sentinel.adapter.spring.webmvc.SentinelWebInterceptor}.
		 */
		private boolean enabled = true;

		public int getOrder() {
			return this.order;
		}

		public void setOrder(int order) {
			this.order = order;
		}

		public List<String> getUrlPatterns() {
			return urlPatterns;
		}

		public void setUrlPatterns(List<String> urlPatterns) {
			this.urlPatterns = urlPatterns;
		}

		public boolean isEnabled() {
			return enabled;
		}

		public void setEnabled(boolean enabled) {
			this.enabled = enabled;
		}

	}

经测试,在 2.2.1.RELEASE 中该问题已经修复了,只需要将版本改为 2.2.1.RELEASE 或之后的版本即可。