springCloud(F版)(6)——Hystrix断路器、HystrixDashboard断路器监控及Turbine断路器聚合监控

版权声明:原创博文,转载请注明出处 https://blog.csdn.net/qq_15903671/article/details/82688303

前面博文我们实现了一个简单的分布式架构,通过服务集群实现高可用,通过sleuth实现服务跟踪。下面通过Hystrix断路器对服务集群某接口不可用的情况进行识别和反馈,并进一步优化使用HystrixDashboard对断路器进行监控、使用Turbine对断路器监控情况进行聚合分析。

首先,我们将接口服务的消费者进行优化,添加Hystrix断路器来识别接口不可用情况并给出反馈。前面博文中的系统结构,使用zuul集群对接口进行消费,使用一个zuul工程实现balance负载均衡,那么我们首先看看zuul如何实现断路器功能。然后再依次学习一下Ribbon和Feign如何集成Hystrix断路器。

一、zuul的FallbackProvider功能

由于springCloud在不断的更新,因此不同版本的zuul中实现熔断的interface也在不断变化,我们前面博文里搭建的springCloud系统使用的是SpringCloud F版本,Springboot 2.0 版本。经过无数的坑之后,终于找到了zuul在的熔断方法。。。如果你的工程springCloud版本或springboot版本跟我不一致,下面就当没看见吧。。。

在之前做好的zuul工程中添加熔断控制类 client1fallback 实现 FallbackProvider接口,源码如下:

package com.testzuul.zuul;

import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

@Component
public class client1fallback implements FallbackProvider {
    @Override
    public String getRoute() {
        return "service-client1";
    }
    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        System.out.println("route:"+route);
        System.out.println("exception:"+cause.getMessage());
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.OK;
            }

            @Override
            public int getRawStatusCode() throws IOException {
                return 200;
            }

            @Override
            public String getStatusText() throws IOException {
                return "ok";
            }

            @Override
            public void close() {

            }

            @Override
            public InputStream getBody() throws IOException {
                return new ByteArrayInputStream("service-client1 fallback .".getBytes());
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                return headers;
            }
        };
    }
}

为了少走弯路,我连import都粘进来了。。。

其他内容全都没有修改,留意getRoute函数,返回值要跟application name(serviceID)保持一致,用来识别这是哪个微服务的熔断控制类。当然,这也意味着你有多少微服务,就要创建多少个熔断控制类了。

编译运行后,关闭service-client1这个服务集群中的所有服务,测试一下。

启动service-client1服务,再试一次。

zuul集成的断路机制只要是识别微服务是不是还在(刚刚识别的是service-client1这个微服务),而不是具体哪个接口的宕机,下面学习一下在Ribbon中集成Hystrix断路器来进一步处理接口级别的熔断机制。

二、Ribbon集成Hystrix断路器

pom文件中添加Hystrix起步依赖(spring-cloud-starter-netflix-hystrix)

<?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.testribbon</groupId>
    <artifactId>testribbon</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>testribbon</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>com.springcloud</groupId>
        <artifactId>testspringcloud</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>

    <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>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>

    </dependencies>

</project>

修改properties配置文件

eureka.client.serviceUrl.defaultZone=http://10.48.8.231:8761/eureka/
#eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
eureka.instance.prefer-ip-address=true
spring.zipkin.base-url=http://10.48.8.231:9411
#spring.zipkin.base-url=http://localhost:9411
#spring.sleuth.sampler.percentage=1.0
spring.sleuth.sampler.probability=1

server.port: 8751
spring.application.name=testRibbon

**application.java入口类添加注解

@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableHystrix
public class TestribbonApplication {

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

    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

添加接口调用的控制类 clientControler

@RestController
public class clientControler {
    @Autowired
    clientService client;

    @GetMapping(value = "/client1")
    public String client1(@RequestParam String name) {
        return client.client1Service( name );
    }

    @GetMapping(value = "/client2")
    public String client2(@RequestParam String name) {
        return client.client2Service( name );
    }

}

创建接口调用的service类 clientService

@Service
public class clientService {

    @Autowired
    RestTemplate restTemplate;

    @HystrixCommand(fallbackMethod = "client1Error")
    public String client1Service(String name) {
        return restTemplate.getForObject("http://SERVICE-CLIENT1/hi?name="+name,String.class);
    }

    public String client1Error(String name) {
        return "hi,"+name+",sorry,fallback!";
    }

    @HystrixCommand(fallbackMethod = "client2Error")
    public String client2Service(String name) {
        return restTemplate.getForObject("http://SERVICE-CLIENT2/hi?name="+name,String.class);
    }

    public String client2Error(String name) {
        return "hi,"+name+",sorry,fallback!";
    }

}

编译运行后浏览器输入 http://localhost:8751/client1?name=qftest 和  http://localhost:8751/client2?name=qftest

下图是我开了client2,没开client1的效果。

三、Feign集成Hystrix断路器

Feign是自带hystrix断路器的,因此pom文件无需添加新的依赖包。SpringCloud D版本以上断路器默认是关闭的,因此修改配置文件,添加feign.hystrix.enabled=true打开断路器即可

eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/ 
eureka.instance.prefer-ip-address=true
spring.zipkin.base-url=http://localhost:9411 
#spring.sleuth.sampler.percentage=1.0
spring.sleuth.sampler.probability=1

server.port: 8752
spring.application.name=testFeign

#启动feign自带的hystrix断路器
feign.hystrix.enabled=true

**application.java入口类添加注解

@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableHystrix

控制类testcontroler也没有变化

@RestController
public class testcontroler {
    @Autowired
    client1service test1;
    @Autowired
    client2service test2;

    @GetMapping(value = "/client1")
    public String client1(@RequestParam String name) {
        return test1.testFunction( name );
    }

    @GetMapping(value = "/client2")
    public String client2(@RequestParam String name) {
        return test2.testFunction( name );
    }
}

client1service接口则不能只声明个interface函数了,要添加fallback的指定

@FeignClient(value = "service-client1",fallback = Client1serviceimpl.class)
public interface client1service {
    @RequestMapping(value = "/hi",method = RequestMethod.GET)
    String testFunction(@RequestParam(value = "name") String name);
}

其中,FeignClient注解指定了接口对应的微服务service-client1和熔断处理类client1serviceimpl,接口中的每个函数声明都对应着一个微服务接口,这一点没什么变化。

下面添加client1serviceimpl类实现client1service接口,其实是实现fallback。

@Component
public class Client1serviceimpl implements client1service {
    @Override
    public String testFunction(String name) {
         return "hi,"+name+",sorry,fallback!";
    }
}

当feign程序调用接口时,如果接口没有反馈则会快速执行client1serviceimpl中对应的熔断处理函数。

编译运行,效果与Ribbon相同。

四、HystrixDashboard断路器监控

访问接口提示报错信息,说明我们的Hystrix断路器已生效,下面我们以zuul工程为例,通过HystrixDashboard对服务的熔断情况进行查看监控。

pom文件添加基础依赖

<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>

properties配置文件中添加必要的配置信息

#配置 Hystrix Dashboard
management.server.port=9001
management.endpoints.web.base-path=/actuator
management.endpoints.web.exposure.include='*'

入口类添加注解

@EnableHystrix
@EnableHystrixDashboard

重新编译执行zuul程序,浏览器调用zuul接口(反复关闭service-client1和service-client2)看到成功调用和熔断信息后就可以尝试查看熔断情况了。

浏览器输入 http://localhost:8751/hystrix 注意localhost如果不是本地测试的化换成自己的ip、8751是服务的端口号,并不是刚刚配置的management.server.port对应的端口号。如下图

输入要要看的查看的监控信息 http://localhost:9001/actuator/hystrix.stream 这个时候的端口号才是刚刚配置的9001,读取的数据地址是management.endpoints.web.base-path配置的actuator,数据流是hystrix.stream。当然这个url也可以直接粘贴到浏览器上去看具体的数据流内容。如下图:

至此我们已经可以查看某个微服务的熔断信息了,Ribbon和Feign的改造方式基本相同。但是,这种改造方式只能查看某个微服务的熔断情况,当微服务较多时呢?我们希望聚合所有的微服务,将可视化信息集中起来查看,引入下面章节。

五、Turbine断路器聚合监控

Turbine是一个独立的server,同样作为eureka client将自己注册到注册中心,通过配置监控的serviceID从注册中心获取到各service的ip,然后去拉取hystrix.stream数据流进行统一监控。

我将上面创建的Ribbon和Feign都配置了HystrixDashboard,然后启动了这两个负载均衡接口调用程序,下面新创建一个springboot工程,配置成TurbineServer实现断路器的聚合监控。

创建springboot工程命名为turbineserver,修改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.turbine</groupId>
    <artifactId>turbineserver</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>turbineserver</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>com.springcloud</groupId>
        <artifactId>testspringcloud</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <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.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>

        <!-- hystrix起步依赖包 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <!-- hystrix dashboard 依赖包 -->
        <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>
        <!-- turbine 依赖包 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-turbine</artifactId>
        </dependency>
    </dependencies>
</project>

**application.java入口类添加注解

@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@RestController
@EnableHystrix
@EnableHystrixDashboard
@EnableCircuitBreaker
@EnableTurbine

修改application.properties配置文件,添加turbine相关配置

#配置eureka client
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/ 
eureka.instance.prefer-ip-address=true
#配置zipkin服务跟踪
spring.zipkin.base-url=http://localhost:9411  
spring.sleuth.sampler.probability=1

#配置自己的端口和serviceID
server.port: 9004
spring.application.name=turbine-server

#配置 Hystrix Dashboard
management.server.port=9003
management.endpoints.web.base-path=/actuator
management.endpoints.web.exposure.include="*"
management.endpoints.web.cors.allowed-origins="*"
management.endpoints.web.cors.allowed-methods="*"

#配置 turbine
turbine.app-config=testfeign,testribbon
turbine.aggregator.cluster-config=default
turbine.cluster-name-expression=new String("default")
turbine.combine-host-port=true 
turbine.instanceUrlSuffix.default=actuator/hystrix.stream

OK,编译运行看下结果

浏览器输入 http://localhost:9004/turbine.stream看一下数据流情况

浏览器输入 http://localhost:9004/hystrix

页面输入http://localhost:9004/turbine.stream

收工睡觉。

猜你喜欢

转载自blog.csdn.net/qq_15903671/article/details/82688303
今日推荐