使用 Turbine 聚合监控

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qmqm011/article/details/85040692

在使用 Hystrix Dashboard 组件监控服务的熔断状况时,每个服务都有一个 Hystrix Dashboard 主页,当服务数量很多时相当不方便。为了同时监控多个服务的熔断器的状态,可以使用 Turbine。Turbine 用于聚合多个 Hystrix Dashboard,将多个 Hystrix Dashboard 组件的数据放在一个页面上展示,进行集中监控。

创建父项目

本例采用 Maven 多模块结构,首先创建一个父项目 spring-cloud-turbine,其 pom 文件如下:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.wuychn</groupId>
    <artifactId>spring-cloud-turbine</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>eureka-server</module>
        <module>service-provider</module>
        <module>service-consumer-hi</module>
        <module>service-consumer-hello</module>
        <module>turbine-monitor</module>
    </modules>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring.cloud.version>Finchley.RELEASE</spring.cloud.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    
</project>

创建服务注册中心

在父项目下新建一个子模块 eureka-server,作为服务注册中心,其 pom 文件如下:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-cloud-turbine</artifactId>
        <groupId>com.wuychn</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>eureka-server</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

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

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

application.yml:

server:
  port: 9001

spring:
  application:
    name: eureka-server

eureka:
  instance:
    hostname: localhost
  client:
    fetch-registry: false
    register-with-eureka: false
    serviceUrl:
      defaultZone: http://localhost:9001/eureka/

程序启动类:

package com.wuychn;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

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

创建服务提供者

在父项目下新建一个子模块 service-provider,作为服务提供者,其 pom 文件如下:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-cloud-turbine</artifactId>
        <groupId>com.wuychn</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service-provider</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

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

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

application.yml:

server:
  port: 9003

spring:
  application:
    name: service-provider

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9001/eureka/

程序启动类:

package com.wuychn;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class ServiceProviderApplication {

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

}

在 service-provider 中,有两个 Controller,一个是 HiController,一个是 HelloController,它们都有一个 REST API 接口,供服务消费者消费,HiController 如下:

package com.wuychn.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HiController {

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

    @GetMapping("/hi")
    public String hi(String name) {
        return "hi " + name + ", I am from port:" + port;
    }

}

HelloController 如下:

package com.wuychn.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello(String name) {
        return "Hello, " + name;
    }

}

创建服务消费者 service-consumer-hi

在父项目中新建一个子模块 service-consumer-hi,作为服务消费者,它会使用 Feign 调用 service-provider 的 /hi 接口。其 pom 文件如下:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-cloud-turbine</artifactId>
        <groupId>com.wuychn</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service-consumer-hi</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

application.yml:

spring:
  application:
    name: service-consumer-hi
server:
  port: 9004
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9001/eureka/
feign:
  hystrix:
    enabled: true

程序启动类:

package com.wuychn;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableHystrix
@EnableHystrixDashboard
public class ServiceConsumerHiApplication {

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

}

HiController:

package com.wuychn.controller;

import com.wuychn.service.HiService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HiController {

    @Autowired
    private HiService hiService;

    @GetMapping("/hi")
    public String hi(@RequestParam(required = false, defaultValue = "wuychn") String name) {
        return hiService.hi(name);
    }

}

HiService:

package com.wuychn.service;

import com.wuychn.client.HiFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class HiService {

    @Autowired
    private HiFeignClient hiFeignClient;

    public String hi(String name) {
        return hiFeignClient.hi(name);
    }
}

HiFeignClient:

package com.wuychn.client;

import com.wuychn.client.config.FeignConfig;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(value = "service-provider", configuration = FeignConfig.class, fallback = HiFeignFallback.class)
public interface HiFeignClient {

    // 如果不添加@RequestParam注解,会被转化为POST请求,从而报405
    @GetMapping("/hi")
    String hi(@RequestParam(value = "name") String name);
}

@Component
class HiFeignFallback implements HiFeignClient {

    @Override
    public String hi(String name) {
        return "sorry, " + name + ", please wait..";
    }
}

FeignConfig:

package com.wuychn.client.config;

import feign.Retryer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import static java.util.concurrent.TimeUnit.SECONDS;

@Configuration
public class FeignConfig {

    @Bean
    public Retryer reignRetryer() {
        return new Retryer.Default(100, SECONDS.toMillis(1), 5);
    }
}

HystrixDashboardConfig:

package com.wuychn.config;

import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class HystrixDashboardConfig {

    @Bean
    public ServletRegistrationBean getServlet() {
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }


}

创建服务消费者 service-consumer-hello

service-consumer-hello 和 service-consumer-hi 类似,只不过它是调用 service-provider 的 /hello 接口。

创建 turbine-monitor

最后,在父项目下新建一个子项目 turbine-monitor,作为 Turbine 聚合监控的工程,其完整的 pom 文件如下:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-cloud-turbine</artifactId>
        <groupId>com.wuychn</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>turbine-monitor</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-turbine</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
    </dependencies>


</project>

application.yml:

server:
  port: 9006

spring:
  application:
    name: turbine-monitor

turbine:
  aggregator:
    clusterConfig: default
  appConfig: service-consumer-hi,service-consumer-hello
  clusterNameExpression: new String("default")
  instanceUrlSuffix: /hystrix.stream
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9001/eureka/

其中,turbine.aggregatorappConfig 配置了需要监控的服务名,本例中,需要监控的服务有 service-consumer-hi 和 service-consumer-hello。clusterNameExpression 默认为服务名的集群,使用默认就可以。instanceUrlSuffix 和被监控服务中的 registrationBean.addUrlMappings(“/hystrix.stream”) 指定的路径一致。

程序启动类如下:

package com.wuychn;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.turbine.EnableTurbine;

@SpringBootApplication
@EnableTurbine
public class TurbineMonitorApplication {

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

到这里,代码就写完了,整个项目的结构如图:

依次启动 eureka-server、service-provider、service-consumer-hi、service-consumer-hello 和 turbine-monitor,在浏览器中访问 http://localhost:9004/hystrix,在界面上依次输入监控流的地址 http://localhost:9006/turbine.stream、监控间隔时间 2000 毫秒和 title,单击 Monitor Stream,可以看到如下界面:

至此,使用 Turbine 聚合监控完成。

猜你喜欢

转载自blog.csdn.net/qmqm011/article/details/85040692