springCloud学习02之断路器Hystrix-turbine监控-ribbo/feign对Hystrix的支持

版权声明: https://blog.csdn.net/dream_broken/article/details/76269616

        随着Docker的推进,微服务越来越热了.在微服务架构中,我们将业务拆分成一个个的服务,服务与服务之间可以相互调用。为了保证其高可用,单个服务又必须集群部署。由于网络原因或者自身的原因,服务并不能保证服务的100%可用,如果单个服务出现问题,调用这个服务就会出现网络延迟,此时若有大量的网络涌入,会形成任务累计,导致服务瘫痪,甚至导致服务“雪崩”。

       特别是app和api是通过http(如httpClient工具)进行连接通信时,我们一般都是设置个超时而已。但是这仍然有弊端,比如超时设置为2s,网络不稳定出问题了或者api挂了,app不知道啊,仍然会向api发出请求,如果一个业务需要调用多个3个api时,那响应给用户客户端(如浏览器)就起码超过6s了;如果并发量高,还会倒是app积累非常多的进程或线程,消耗了系统资源。如果有这么一个工具,在app端帮助app对api的响应情况进行记录,如果某个api的不响应了或者经常响应超时,那app再次请求该api时,那工具立刻识别到该api是不正常的,立刻告诉app。当api又正常了,那app的请求又会正常到达api。

      Hystrix就是专门为解决这些问题的。

  本博文的代码例子,github上。

 熔断器

   我们先简单了解下什么叫熔断器。


   spring cloud已经集成了Hystrix了。上一篇博文学习了eureka服务发现-提供者-消费者ribbo-feign,spring cloud也已经对ribbon和feign集成了Hystrix.下面我们分别学习下。

  ribbon对Hystrix的支持

   在上一篇博文中,已经创建有ribbon的项目了eureka-app-ribbon,复制一份修改名称为eureka-app-ribbon-hystrix,
pom.xml增加
<!-- hystrix的支持 -->
       <dependency>  
            <groupId>org.springframework.cloud</groupId>  
            <artifactId>spring-cloud-starter-hystrix</artifactId>  
        </dependency>  
        <!-- 健康检查 -->
        <dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-actuator</artifactId>  
        </dependency>  

application.properties
logging.config=classpath:logback.xml
logging.path=d:/logs

##tomcat set###

# eureka的默认端口是8761
server.port=7081
server.session-timeout=60
###########

spring.application.name=app-user

#像eureka服务注册信息时,使用ip地址,默认使用hostname
eureka.instance.preferIpAddress=true
#服务的instance-id默认默认值是${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}} ,
#也就是机器主机名:应用名称:应用端口
eureka.instance.instance-id=${spring.cloud.client.ipAddress}:${server.port}

# 开启健康检查(需要spring-boot-starter-actuator依赖)
eureka.client.healthcheck.enabled=true;
# 续约更新时间间隔(默认30秒)
eureka.instance.lease-renewal-interval-in-seconds=30
# 续约到期时间(默认90秒)
eureka.instance.lease-expiration-duration-in-seconds=10

#eureka的服务地址
eureka.client.serviceUrl.defaultZone=http://01.server.eureka:8081/eureka/

#ribbo负载均衡策略配置,默认是依次轮询
API-USER-SERVER.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule

#Hystrix是否启用超时时间
hystrix.command.default.execution.timeout.enabled=true;
#Hystrix断路器的超时时间,默认是1s
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=2000

UserController.java
package com.fei.springcloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;

@Controller
@RequestMapping("/user")
public class UserController {

	@Autowired
    private RestTemplate restTemplate;

	@HystrixCommand(fallbackMethod = "findError") //如果请求失败或超时
    @GetMapping(value = "/find")
    @ResponseBody
    public String find() {
    	//url中对应api提供者的名称,全大写
		System.out.println("向api提供者发起请求........");
    	String s = restTemplate.getForEntity("http://API-USER-SERVER/user/find/123", String.class).getBody();
        return s;
    }
	
	
	public String findError(){
		return "查询用户,调用api失败....";
	}
	
   
}

看到在接受请求的方法上添加注解@HystrixCommand(fallbackMethod = "findError"),如果Hystrix中对该请求进行了无效处理,则立即执行findError()方法。@HystrixCommand有好几个属性,后面再深入研究
启动类Application.java
package com.fei.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@EnableEurekaClient 
@SpringBootApplication
@EnableHystrix    //增加hystrix断路器
public class Application {

	@Bean //定义REST客户端,RestTemplate实例
    @LoadBalanced //开启负债均衡的能力
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
	
	public static void main(String[] args) {

		SpringApplication.run(Application.class, args);
	}
}

增加了注解@EnableHystrix。
测试,启动eureka服务,启动eureka-app-ribbon-hystrix,先不用启动api提供者。浏览器访问http://127.0.0.1:7081/user/find,发现返回的是“查询用户,调用api失败....”,然后启动api提供者,稍等一会,再次发起请求,返回的是“张三 服务端端口:9082

  feign对Hystrix的支持

  feign已经自带断路器了,就像自带了ribbon的负载均衡,如果想关闭feign自带的断路器,application.properties中添加
feign.hystrix.enabled=false

  既然已经自带hystrix,那pom.xml就不需要添加hystrix的支持了。细心的人在上一篇博文学习feign的时候,使用@FeignClient的时候,看@FeignClient的源码就会发现有个fallback支持。
  上篇博文已经有项目eureka-app-feign了,复制一份名称为eureka-app-feign-hystrix.

UserService.java
package com.fei.springcloud.service;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(value="API-USER-SERVER",fallback=UserServiceErrorImpl.class)
public interface UserService {

	@GetMapping(value="/user/find/{id}")
	String find(@PathVariable("id") String id);
}
增加fallback的支持,UserServiceErrorImpl是UserService的实现类
package com.fei.springcloud.service;

import org.springframework.stereotype.Component;

@Component
public class UserServiceErrorImpl implements UserService{

	@Override
	public String find(String id) {
		return "根据id查询用户,调用api提供者失败...";
	}

}

application.properties
logging.config=classpath:logback.xml
logging.path=d:/logs

##tomcat set###

# eureka的默认端口是8761
server.port=7081
server.session-timeout=60
###########

spring.application.name=app-user

#像eureka服务注册信息时,使用ip地址,默认使用hostname
eureka.instance.preferIpAddress=true

# 续约更新时间间隔(默认30秒)
eureka.instance.lease-renewal-interval-in-seconds=30
# 续约到期时间(默认90秒)
eureka.instance.lease-expiration-duration-in-seconds=10

#服务的instance-id默认默认值是${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}} ,
#也就是机器主机名:应用名称:应用端口
eureka.instance.instance-id=${spring.cloud.client.ipAddress}:${server.port}
#eureka的服务地址
eureka.client.serviceUrl.defaultZone=http://01.server.eureka:8081/eureka/

#开启健康检查
eureka.client.healthcheck.enabled=true
#开启hystrix,默认是false,这个是必须的开放,否则会出现找不到消费者或者拒绝连接的错误
feign.hystrix.enabled=true
#ribbo负载均衡策略配置,默认是依次轮询
API-USER-SERVER.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
#Hystrix是否启用超时时间
hystrix.command.default.execution.timeout.enabled=true;
#Hystrix断路器的超时时间,默认是1s
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=2000
feign.hystrix.enabled=true这个默认是false,如果使用了hystrix,则必须配置为true,否则会出现找不到消费者就报错,或者拒绝连接等异常报错.


启动类Application.java也增加注解@EnableHystrix
启动eureka服务,启动eureka-app-feign-hystrix,暂时不启动api提供者。
访问http://127.0.0.1:7081/user/find,返回“根据id查询用户,调用api提供者失败...

Hystrix Dashboard

 上面学习了ribbon和feign的情况下使用hystrix对url的监控。现在学习下hystrix dashboard界面的查看。

pom.xml文件中,必须有
		<!-- hystrix的支持 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-hystrix</artifactId>
		</dependency>
		<!-- 健康检查 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<!-- hystrix dashboard的支持 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
		</dependency>
启动类加上@EnableHystrixDashboard,如
package com.fei.springcloud;

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

@SpringBootApplication
@EnableEurekaClient 
@EnableFeignClients //用于启动Fegin功能
@EnableHystrix    //增加hystrix断路器
@EnableHystrixDashboard  //支持hystrix dashboard
public class Application {

	
	
	public static void main(String[] args) {

		SpringApplication.run(Application.class, args);
	}
}

启动后,访问消费者app的ip+端口/hystrix,如http://127.0.0.1:7081/hystrix


图中的那几行英文
Cluster via Turbine (default cluster): http://turbine-hostname:port/turbine.stream
Cluster via Turbine (custom cluster): http://turbine-hostname:port/turbine.stream?cluster=[clusterName]
Single Hystrix App: http://hystrix-app:port/hystrix.stream

大概意思就是如果查看默认集群使用第一个url,查看指定集群使用第二个url,单个应用的监控使用最后一个,我们暂时只演示单个应用的所以在输入框中输入:
http://127.0.0.1:7081/hystrix.stream输入之后点击 monitor,进入页面。

发现都是loading...
这是因为还没有任何请求,如果我们访问http://127.0.0.1:7081/hystrix.stream,你会看到页面打印很多ping。
那我们先发起一个访问请求http://127.0.0.1:7081/user/find,然后再回到监控界面,就发现loading...没有了

由于没有启动api消费者,所以刚刚上面的请求其实是404,也就是失败Failure,所以看到1是红色的。
至于其他都是什么意思,可以看官网的Hystrix Dashboard Wiki


Turbine

   上面查看hystrix dashboard的时候,是直接访问单个app的hystrix dashboard的,那如果有很多个app消费者呢?总不能一一打开来看吧。为此,Netflix提供了一个开源项目(Turbine)来提供把多个hystrix.stream的内容聚合为一个数据源供Dashboard展示。

  使用sping boot搭建个hystrix-dashboard-turbine项目,用来收集各个app消费者的hystrix监控信息。
pom.xml
<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.fei.springcloud</groupId>
	<artifactId>springcloud-eureka-hystrix-turbine</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<description>turbine收集显示各个hystrix的信息</description>

	<!-- 依赖仓库 设置从aliyun仓库下载 -->
	<repositories>
		<repository>
			<id>alimaven</id>
			<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
			<releases>
				<enabled>true</enabled>
			</releases>
		</repository>
	</repositories>
	<!-- 插件依赖仓库 -->
	<pluginRepositories>
		<pluginRepository>
			<id>alimaven</id>
			<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
			<releases>
				<enabled>true</enabled>
			</releases>
		</pluginRepository>
	</pluginRepositories>

	<properties>

		<!-- 文件拷贝时的编码 -->
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<!-- 编译时的编码 -->
		<maven.compiler.encoding>UTF-8</maven.compiler.encoding>

		<java.version>1.8</java.version>
		<maven.compiler.source>1.8</maven.compiler.source>
		<maven.compiler.target>1.8</maven.compiler.target>

	</properties>

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

	</parent>

	<dependencies>
        
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-turbine</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-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-hystrix-dashboard</artifactId>
		</dependency>

	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Dalston.RELEASE</version>
				<type>pom</type>
				<scope>import</scope><!-- 这个不能丢 -->
			</dependency>

		</dependencies>
	</dependencyManagement>

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

</project>

配置文件application.properties
logging.config=classpath:logback.xml
logging.path=d:/logs

##tomcat set###


server.port=6081
server.session-timeout=60
###########

spring.application.name=hystrix-turebin

#配置Eureka中的serviceId列表,表明监控哪些服务,也就是app消费者的应用名称,多个时用英文逗号隔开
#turbine.appConfig=app-user-ribbon-hystrix,app-user-feign-hystrix
turbine.appConfig=APP-USER-RIBBON-HYSTRIX,APP-USER-FEIGN-HYSTRIX

turbine.aggregator.clusterConfig=default
turbine.clusterNameExpression=new String("default")

#像eureka服务注册信息时,使用ip地址,默认使用hostname
eureka.instance.preferIpAddress=true
#服务的instance-id默认默认值是${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}} ,
#也就是机器主机名:应用名称:应用端口
eureka.instance.instance-id=${spring.cloud.client.ipAddress}:${server.port}
#eureka的服务地址,/eureka是固定的
eureka.client.serviceUrl.defaultZone=http://01.server.eureka:8081/eureka/

我们上面学习的时候,已经有2个app消费者了eureka-app-ribbon-hystrix和eureka-app-feign-hystrix,修改他们的配置文件中的端口号和应用名称,比如eureka-app-ribbon-hystrix是7081,eureka-app-feign-hystrix是7082,

turbine的启动类Application.java
package com.fei.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.netflix.turbine.EnableTurbine;
  
@SpringBootApplication
@EnableHystrixDashboard
@EnableTurbine
public class Application {

	public static void main(String[] args) {

		SpringApplication.run(Application.class, args);
	}
}

将eureka-server服务,eureka-app-ribbon-hystrix,eureka-app-feign-hystrix,eureka-turbine都启动起来。访问eureka服务http://127.0.0.1:8081/,看到这样(由于配置文件里面配置了一些过期时间之类,可能显示不完整,多刷新几次页面)


为了防止监控界面出现loading...,先都调用下ribbon和feign的访问http://127.0.0.1:7081/user/find,http://127.0.0.1:7082/user/find,然后访问turbine的监控界面http://127.0.0.1:6081/hystrix,出现那小熊界面


 然后再输入框输入http://127.0.0.1:6081/turbine.stream,注意是turbine.stream,而不是hystrix.stream了,然后点击监控,看到出现2个监控列表了。




猜你喜欢

转载自blog.csdn.net/dream_broken/article/details/76269616