您的位置:首页 > 编程语言 > Java开发

SpringCloud之服务容错保护Spring Cloud Hystrix实例

2018-01-10 18:08 363 查看

一、断路器简介

在微服务架构中,将系统拆分成了很多服务单元,各单元的应用间通过服务注册与订阅的方式互相依赖。由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服务自身间题出现调用故障或延迟,而这些问题会直接导致调用方的对外服务也出现延迟,若此时调用方的请求不断增加,最后就会因等待出现故障的依赖方响应形成任务积压,最终导致自身服务的瘫痪。

在微服务架构中,存在着那么多的服务单元,若一个单元出现故障,就很容易因依赖关系而引发故障的蔓延,最终导致整个系统的瘫痪,这样的架构相较传统架构更加不稳定。为了解决这样的问题,产生了断路器等一系列的服务保护机制。

针对上述问题,Spring Cloud Hystrix实现了断路器、线程隔离等一系列服务保护功能。它也是基于Netflix的开源框架Hystrix实现的,该框架的目标在于通过控制那些访问远程系统、服务和第三方库的节点, 从而对延迟和故障提供更强大的容错能力。Hystrix具备服务降级、服务熔断、线程和信号隔离、请求缓存、请求合并以及服务监控等强大功能。

二、前期准备

在开始使用Spring Cloud Hystrix实现断路器之前,我们先用之前实现的一些内容作为基础,构建一个如下图架构所示的服务调用关系。



我们在这里需要启动的工程有如下一些:(都是前二章的项目)

一个服务注册中心,eurekaserver,端口为5555;
helloservice工程跑了三个实例,端口分别为5556、5557、5558,分别向服务注册中心注册;
sercvice-ribbon端口为5560,向服务注册中心注册,端口为5560;
当sercvice-ribbon通过restTemplate调用helloservice的hello接口时,因为用ribbon进行了负载均衡,会轮流的调用helloservice:5556、5557和5558端口的hello接口;

在未加入断路器之前,关闭5556的实例, 发送GET请求到http://localhost:5560/, 可以获得下面的输出:



三、实例(在原来ribbon项目上改造)

(1)pom.xml,添加hystrix依赖

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

(2)启动类增加@EnableCircuitBreaker

@EnableCircuitBreaker
@EnableDiscoveryClient
@SpringBootApplication
public class SpringcloudribbonApplication {

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

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

(3)HelloService改造
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;

@HystrixCommand(fallbackMethod = "helloError")
public String helloService() {
return restTemplate.getForObject("http://HELLOSERVER/hello", String.class);
}

public String helloError(){
return "hello error~";
}
}

(4)HelloController
@RestController
public class HelloController {
@Autowired
HelloService helloService;

@RequestMapping("/hello")
public String hello() {
return helloService.helloService();
}
}

(5)测试(关掉helloserver的5556端口,启动ribbon,地址:http://127.0.0.1:5560/hello)



四、原理分析

通过上面的快速入门示例,我们对Hystrix的使用场景和使用方法已经有了一个基础的认识。接下来我们通过解读NetflixHystrix官方的流程图来详细了解 一下: 当一个请求调用了相关服务依赖之后Hystrix是如何工作的(即如上例中所示,当访问了http://127.0.0.1:5560/hello请求之后, 在SERVICE-RIBBON中是如何处理的)。

工作流程



(1)创建HystrixCommand或HystrixObservableCommand对象

HystrixCommand: 用在依赖的服务返回单个操作结果的时候。
HystrixObservableCommand: 用在依赖的服务返回多个操作结果的时候。

(2)命令执行
从图中我们可以看到一共存在4种命令的执行方式,而 Hystrix在执行 时 会根据创建的Command对象以及具体的情况来选择一个执行。其中HystrixComrnand实现了下面两个执行方式。

execute (): 同步执行,从依赖的服务 返回一个单一的结果对象,或是在发生错误的时候抛出异常。
queue (): 异步执行,直接返回一个Future对象,其中包含了服务 执行结束时要返回的单一结果对象。

R value = command.execute() ;
Future<R> fValue = command.queue() ;

而HystrixObservableCommand实现了另外两种 执行方式。

observe () : 返回Observable对象,它代表了操作的多个结果,它是一个Hot Observable。
toObservable(): 同样会返回Observable对象,也代表了操作的多个结果,但它返回的是一个Cold Observable。

Observable<R> ohValue = command.observe();
Observable<R> ocValue = command.toObservable();<
4000
/pre>
(3)结果是否被缓存
若当前命令的请求缓存功能是被启用的,并且该命令缓存命中,那么缓存的结果会立即以Observable 对象的形式返回。

(4)断路器是否打开

在命令结果没有缓存命中的时候, Hystrix在执行命令前需要检查断路器是否为打开状态:

如果断路器是打开的,那么Hystrix不会执行命令,而是转接到fallback处理逻辑(对应下面第8步)。
如果断路器是关闭的, 那么Hystrix跳到第5步,检查是否有可用资源来 执行命令。关于断路器的具体实现细节,后续会做更加详细的分析。

(5)线程池I请求队列I信号量是否占满
如果与命令相关的线程池和请求队列,或者信号量(不使用线程池的时候)已经被占满, 那么Hystrix也不会执行命令,而是转接到fallback处理逻辑(对应下面第8步)。

(6)HystrixObservableCommand.construct()或HystrixCommand.run()Hystrix会根据我们编写的方法来决定采取什么样的方式去请求依赖服务。

HystrixCommand.run(): 返回一个单一 的结果,或者抛出异常。
HystrixObservableCommand.construct(): 返回一个Observable对象来发射多个结果,或通过onError发送错误通知。

(7)计算断路器的健康度

Hystrix会将“ 成功 ”、“ 失败”、“ 拒绝”、“ 超时 ”等信息报告给断路器,而断路器会维护一组计数器来统计这些数据。

断路器会使用这些统计数据来决定是否要将断路器打开,来对某个依赖服务的请求进行 “熔断/短路 ”,直到恢复期结束。 若在恢复期结束后, 根据统计数据判断如果还是未达到健康指标,就再次 “ 熔断/短路 ”。

(8)fallback处理

当命令执行失败的时候, Hystrix会进入fallback尝试回退处理,我们通常也称该操作为“服务降级”。

(9)返回成功的响应

具体详解,暂无

五、Hystrix仪表盘

在断路器原理的介绍中 ,我们多次提到关千请求命令的度量指标的判断。这些度量指标都是HystrixComrnand和HystrixObservableComrnand实例在执行过程中记录的重要信息, 它们除了在Hystrix断路器实现中使用之外,对千系统运维也有非常大的帮助 。这些指标信息会以“滚动时间窗”与“桶”结合的方式进行汇总,并在内存中驻留一段时间,以供内部或外部进行查询使用,Hystrix仪表盘就是这些指标内容的消费者之一 。

将在Hystrix入门例子的基础上,构建一个Hystrix Dashboard来对RIBBON-CONSUMER实现监控,完成后的架构如下图所示。



(1)pom.xml(在原有ribbon基础上改)

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

(2)入口类增加@EnableHystrixDashboard

@EnableHystrixDashboard
@EnableCircuitBreaker @EnableDiscoveryClient @SpringBootApplication public class SpringcloudribbonApplication { public static void main(String[] args) { SpringApplication.run(SpringcloudribbonApplication.class, args); } @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } }

(3)application.yml

server:
port: 5560

eureka:
client:
serviceUrl:
defaultZone: http://localhost:5555/eureka/ 
spring:
application:
name: service-ribbon

(4)测试:
到这里 我们已经完成了基本配置,接下来可以启动该应用,并访问http://127.0.0.1:5560/hystrix。 可以看到如下页面:



这是Hystrix Dashboard的监控首页,该页面中并没有具体的监控信息。从页面的文字内容中我们可以知道,Hystrix Dashboard共支持三种不同的监控方式,如下所示。

默认的集群监控:通过URL http://turbine-hostname:port/turbine.stream开启,实现对默认集群的监控。 指定的集群监控:通过URL http://turbine-hostname:port/turbine.strearn?cluster= [clusterName]开启,实现对clusterName集群的监控。

单体应用的监控:通过URL http: //hystrix-app:port/hystrix.stream开启,实现对具体某个服务实例的监控。

既然Hystrix Dashboard监控单实例节点需要通过访间实例的/hystrix.stream接口来实现,我们自然需要为服务实例添加这个端点,而添加该功能的步骤也同样简单, 只需要下面两步。(备注:前面已经添加过,无需重复添加)
在服务实例pom.xml中的dependencies节点中新增spring-boot-starter-actuator监控模块以开启监控相关的端点,并确保已经引入断路器的依赖spring-cloud-starter-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>


确保在服务实例的主类中已经使用@EnableCircuitBreaker注解,开启了断路器功能。

@EnableHystrix
@EnableHystrixDashboard
@EnableCircuitBreaker @EnableDiscoveryClient @SpringBootApplication public class SpringcloudribbonApplication { public static void main(String[] args) { SpringApplication.run(SpringcloudribbonApplication.class, args); } @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } }


到这里已经完成了所有的配置,在Hystrix Dashboard的首页输入http://127.0.0.1:5560/hystrix.strearn, 可以看到已启动对RIBBON-CONSUMER的监控,单击MonitorStream按钮,可以看到如下页面:



在确保服务都存在的情况下:




在对该页面进行介绍之前,先看看在首页中我们还没有介绍的另外两个参数。

Delay: 该参数用来控制服务器上轮询监控信息的延迟时间,默认为 2000 毫秒,可以通过配置该属性来降低客户端的网络和CPU消耗。
Title: 该参数对应了上图头部标题Hystrix Stream之后的内容,默认会使用具体监控实例的URL, 可以通过配置该信息来展示更合适的标题。

可以在监控信息的左上部找到两个重要的图形信息:一个实心圆和一条曲线。
实心圆:其有两种含义。通过颜色的变化代表了实例的健康程度,如下图所示,它的健康度从绿色、黄色、橙色、红色递减。该实心圆除了颜色的变化之外,它的大小也会根据实例的请求流量发生变化,流量越大该实心圆就越大。所以通过该实心圆的展示,我们可以在大量的实例中快速发现故障实例和高压力实例。
曲线:用来记录2分钟内流量的相对变化,可以通过它来观察流量的上升和下降趋势。



其他一些数量指标如下图所示:




新手一枚,欢迎拍砖~ ~ ~

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐