微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用(RPC),Spring Cloud可以用RestTemplate+Ribbon和Feign来调用。为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。
为了解决这个问题,提出了断路器模型。
1、断路器简介
Netflix创建了一个名为hystrix的库,用于实现断路器模式。在微服务体系结构中,通常有多个服务调用层。如下图:
底层的服务如果出现故障,会导致连锁故障。当对特定的服务的调用的不可用达到一个阀值(Hystric 是5秒20次) 断路器将会被打开。
断路打开后,可用避免连锁故障,fallback方法可以直接返回一个固定值
2、ribbon使用断路器
A、pox.xml文件中加入spring-cloud-starter-netflix-hystrix的起步依赖:
<!-- hystrix断容器 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>${spring-cloud.hystrix.version}</version>
</dependency>
B、在程序的启动类EurekaRibbonApplication 加@EnableHystrix注解开启Hystrix
spring cloud中discovery service有许多种实现(eureka、consul、zookeeper等等),@EnableDiscoveryClient基于spring-cloud-commons, @EnableEurekaClient基于spring-cloud-netflix。
其实用更简单的话来说,就是如果选用的注册中心是eureka,那么就推荐@EnableEurekaClient,如果是其他的注册中心,那么推荐使用@EnableDiscoveryClient。
C、改造HelloService类,在hiService方法上加上@HystrixCommand注解。并指定了fallbackMethod熔断方法,代码如下:
@HystrixCommand(fallbackMethod = "hiError")
public String hiService(String name) {
return restTemplate.getForObject("http://EUREKA-CLIENT/hello?name=" + name, String.class);
}
public String hiError(String name) {
return "hello " + name + ",sorry,error!";
}
D、启动测试
启动:eureka-ribbon 工程,当我们访问http://localhost:8764/hello?name=adou,浏览器显示:
hello adou,i am from port:8762
关闭客户端eureka-client,再访问http://localhost:8764/hello?name=adou,浏览器会显示:
hello ,adou,orry,error!
说明当 eureka-client工程不可用的时候,eureka-ribbon调用 service-hello的API接口时,会执行快速失败,直接返回一组字符串,而不是等待响应超时,这很好的控制了容器的线程阻塞。
3、Feign使用断路器
a、导入依赖(不加)
b、application.yml
Feign是自带断路器的,在D版本的Spring Cloud之后,它没有默认打开。需要在配置文件中配置打开它。
feign:
hystrix:
enabled: true
c、添加EurekaClientServiceHystric
@Component
public class EurekaClientServiceHystric implements EurekaClientService {
@Override
public String home(String name) {
return "sorry "+name;
}
}
d、在FeignClient的EurekaFeignApplication接口的注解中加上fallback的指定类就行了:
@FeignClient(value = "EUREKA-CLIENT", fallback = EurekaClientServiceHystric.class)
public interface EurekaClientService {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
String home(@RequestParam(value = "name") String name);
}
e、启动测试
启动四eureka-feign工程,浏览器打开http://localhost:8765/hello?name=adou,注意此时eureka-client工程没有启动,网页显示:
sorry adou
打开eureka-client工程,再次访问,浏览器显示:
hello adou,i am from port:8762
4、Hystrix Dashboard简介
Hystrix Dashboard是作为断路器状态的一个组件,提供了数据监控和友好的图形化界面
a.改造eureka-client
pom的工程文件引入相应的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
程序的入口ServiceHiApplication类,加上@EnableHystrix注解开启断路器
并且需要在程序中声明断路点HystrixCommand;加上@EnableHystrixDashboard注解,开启HystrixDashboard
HelloController
@HystrixCommand(fallbackMethod = "hiError")
public String sayHi(@RequestParam String name) {
return eurekaClientService.home(name);
}
public String hiError(String name) {
return "hello,"+name+",sorry,error!";
}
运行程序: 依次开启eureka-server 和eureka-feign
b.Hystrix Dashboard图形展示
打开http://localhost:8762/actuator/hystrix.stream
问题:http://localhost:8762/actuator/hystrix.stream 404 springboot2.0不行,1.5可以
启动项加入
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet() {
ServletRegistrationBean registration = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
registration.addUrlMappings("/actuator/hystrix.stream");
return registration;
}
打开localhost:8762/hystrix 可以看见以下界面:
在界面依次输入:http://localhost:8762/actuator/hystrix.stream 、2000 、miya,点确定
一直处于加载中国
在另一个窗口输入: http://localhost:8762/hello?name=amao
重新刷新hystrix.stream网页,你会看到良好的图形化界面:
5、Turbine简介
看单个的Hystrix Dashboard的数据并没有什么多大的价值,要想看这个系统的Hystrix Dashboard数据就需要用到Hystrix Turbine。Hystrix Turbine将每个服务Hystrix Dashboard数据进行了整合。Hystrix Turbine的使用非常简单,只需要引入相应的依赖和加上注解和配置就可以了。
a.准备工作
eureka-client2同eureka-client配置
b.创建eureka-turbine
引入相应的依赖:
<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.boot</groupId>
<artifactId>spring-boot-starter-actuator</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-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
</dependencies>
入口类ServiceTurbineApplication加上注解@EnableTurbine
开启turbine,@EnableTurbine注解包含了@EnableDiscoveryClient注解,即开启了注册服务。
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@RestController
@EnableHystrix
@EnableHystrixDashboard
@EnableCircuitBreaker
@EnableTurbine
public class EurekaTurbineApplication {
/**
* http://localhost:8764/turbine.stream
*/
public static void main(String[] args) {
SpringApplication.run( EurekaTurbineApplication.class, args );
}
}
配置文件application.yml
server:
port: 8764
spring:
application:
name: eureka-turbine
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
management:
endpoints:
web:
exposure:
include: "*"
cors:
allowed-origins: "*"
allowed-methods: "*"
turbine:
app-config: eureka-client,eureka-client2
aggregator:
clusterConfig: default
clusterNameExpression: new String("default")
combine-host: true
instanceUrlSuffix:
default: actuator/hystrix.stream
Turbine演示
依次开启eureka-server、eureka-client、eureka-client2、eureka-turbine工程。
-
打开浏览器输入:http://localhost:8764/turbine.stream,界面如下:
-
ping
data: {“rollingCountFallbackSuccess”:0,“rollingCountFallbackFailure”:0,"propertyValue_circuitBreakerRequestVolumeThr
依次请求:http://localhost:8762/hello?name=amao
打开:http://localhost:8763/hystrix,输入监控流http://localhost:8764/turbine.stream 2000 miya
点击monitor stream 进入页面:
可以看到这个页面聚合了2个service的hystrix dashbord数据(因为是集群所以例子看不出)