Hystrix服务熔断,监控,服务降级,超时设置的代码实现
一. 服务容错
在微服务架构中通常会有多个服务层调用,如果某个服务不可用,导致级联故障,造成整个系统不可用的情况被称为雪崩效应.

SpringCloud中防雪崩的利器就是SpringCloud Hystrix.
一. 熔断器概述
1. 熔断器产生的背景
在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用(RPC),在Spring Cloud可以用RestTemplate+Ribbon和Feign来调用.为了保证其高可用,单个服务通常会集群部署.由于网络原因或者自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet容器的线程资源会被消耗完毕,导致服务瘫痪.服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应.
为了解决这个问题,业界提出了断路器模型.
2. Hystrix概念
Netflix创建了一个名为Hystrix的库,实现了断路(熔断)器的模式.“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩的发生.
Netflix has created a library called Hystrix that implements the circuit breaker pattern. In a microservice architecture it is common to have multiple layers of service calls.
3. 熔断器工作机制
当对特定服务的调用次数不可用,达到一个阀值(Hystrix 是5秒20次)时,断路器将会被打开.

断路器被打开后,将可以避免连锁故障的发生,fallback方法可以直接返回一个固定值,而不会一直等待直到超时发生.
二. 熔断器作用

1. 依赖隔离,避免雪崩
当我们服务相互之间调用的时候,如果一方发生了服务不可用,将可能导致多个相关的服务都不可用,甚至导致最后所有的服务不可用,从而系统瘫痪.而Hystrix完美的避免了这个雪崩的情况.当服务A不可用时,将返回一个自定义的本地信息,并且接下来的服务将不会调用服务提供者,提供更加快速的响应.当过了一定时间之后,服务又将会尝试去连接后台服务,一旦成功,接下来熔断器将失去作用.
Hystrix的依赖隔离类似于Docker的舱壁模式,Docker通过舱壁模式实现进程隔离,使容器之间互不影响.而Hystrix使用该模式实现的是线程池隔离,会为每个Hystrixcommand创建一个独立的线程池,这样就算某个在HystrixCommand包装下的依赖服务出现延迟过高的情况,也只是对该依赖的服务的调用产生影响,并不会拖慢其他服务.
使用了HystrixCommand来将某个函数包装成Hystrix命令时,Hystrix框架就会自动的为这个函数实现依赖隔离.所以依赖隔离、服务降级在使用的时候都是一体化实现的,这样利用Hystrix来实现服务容错保护在编程模型上就非常方便了,处理依赖隔离、服务降级之外、hystrix还有一个重要元素-服务熔断.
2. 提供了准实时的调用监控界面
除了隔离依赖服务的调用以外,Hystrix还提供了准实时的调用监控(Hystrix Dashboard),Hystrix会持续地记录所有通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少请求多少成功,多少失败等. Netflix通过hystrix-metrics-event-stream
项目实现了对以上指标的监控.Spring Cloud也提供了Hystrix Dashboard的整合,对监控内容转化成可视化界面.
3. 服务降级
- 优先保障核心业务功能,非核心服务不可用或弱可用;
- 通过HystrixCommand注解指定;
- fallbackMethod(回退函数)中具体实现降级逻辑.
4. 服务熔断--Circuit Breaker
断路器--->及时切断故障电路.
微服务和分布式中,容错是必须要考虑的,通常的做法有两种,一种是重试机制,对于可预期的短暂故障问题可以使用重试,第一次不成功在试一次就可能成功.
但是对于重试不能解决的问题,就要使用断路器模式.断路器模式是将受保护的服务封装在一个可以监控故障的断路器对象里面,当故障达到一定的值断路器将会跳闸,断路器对象返回错误.

这幅图描述了断路器模式状态机,在上图状态机有三种状态: Closed、open、half open.
- 1️⃣. closed是熔断器的关闭状态,调用失败次数累计到了一定预值或者一定的比例,就会启动熔断机制;
- 2️⃣. open是熔断器打开状态,此时对服务都直接返回错误,但设计了一个时钟选项,默认的时钟到了这个时间后就会进入半熔断状态,也就是HalfOpen;
- 3️⃣. HalfOpen允许定量的服务请求,如果调用都成功或者一定的比例,则认为恢复了,就会关闭熔断器,否则认为还没好,又回到熔断器打开状态.

上面是三个参数就是控制熔断器的关键参数,默认的时钟达到一定的时间进入半熔断状态.
circuitBreaker.sleepWindowInMilliseconds:时间窗口,断路器确定是否需要打开统计一些请求和错误数据的时候,有个时间范围,这个时间范围就被称为时间窗口.当断路器打开对主逻辑进行熔断之后,Hystrix会启动一个休眠时间窗,在这个时间窗内降级逻辑是临时的成为主逻辑,当休眠时间窗到期断路器将进入半开状态,释放一次请求到原来的主逻辑上,如果此次请求正常返回,那么断路器将继续闭合,主逻辑恢复.如果这次请求依然有问题,断路器将继续进入打开状态,休眠时间窗继续计时.
这个参数配置的10000毫秒,休眠时间窗结束后,会将断路器设置成half open,尝试熔断请求命令,如果依然失败就将断路器设置为打开状态,如果成功就设置为关闭状态.
circuitBreaker.requestVolumeThreshold: 设置在滚动时间窗口中断路器的最小请求数,设置的是10.
circuitBreaker.errorThresholdPercentage: 设置断路器打开的错误百分比条件,这里设置的是60.表示在滚动时间窗口中如果发生10次调用,在这10次调用中有7次发生了异常,那就是70%异常超过了60%,此时断路器将会被设置为打开状态,否则就会设置为关闭状态.
三. Hystrix熔断实现
1. Ribbon中实现服务熔断
1.1 添加依赖
<dependencies>
<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-netflix-ribbon</artifactId>
</dependency>
<!--添加熔断依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>
1.2 入口类添加@EnableHystrix注解,开启熔断功能
package com.syc.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
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;
@SpringBootApplication
@EnableDiscoveryClient //注意:必须是@EnableDiscoveryClient注解,不能是@EnableEurekaClient,否则无法实现负载均衡.
//@EnableEurekaClient
@EnableHystrix
public class ServiceRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceRibbonApplication.class, args);
}
//创建负载均衡组件
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
1.3 改造HelloController类
package com.syc.cloud.web;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.syc.cloud.service.RibbonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@Autowired
private RibbonService helloService;
//给需要降级的方法加上注解@HystrixCommand
//@HystrixCommand(fallbackMethod = "helloError")
@RequestMapping(value = "/hello")
public String hello(@RequestParam String name){
return helloService.helloService(name);
}
/*熔断处理*/
public String helloError(String name) {
return "Hello,"+name+". Sorry,please check your network!";
}
}
1.4 熔断测试

1.5 入口类添加@EnableCircuitBreaker注解
package com.syc.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
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;
/**
*
*/
@SpringBootApplication
@EnableDiscoveryClient //注意:必须是@EnableDiscoveryClient注解,不能是@EnableEurekaClient,否则无法实现负载均衡.
//@EnableEurekaClient
@EnableHystrix
@EnableCircuitBreaker //开启服务熔断功能
public class ServiceRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceRibbonApplication.class, args);
}
//创建负载均衡组件
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
1.6 HelloController上统一配置降级方法
package com.syc.cloud.web;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.syc.cloud.service.RibbonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@DefaultProperties(defaultFallback = "defaultfallback") //controller上配置统一降级处理方法
public class HelloController {
@Autowired
private RibbonService helloService;
//给需要降级的方法加上注解@HystrixCommand
//@HystrixCommand(fallbackMethod = "helloError")
@HystrixCommand()
@RequestMapping(value = "/hello")
public String hello(@RequestParam String name){
return helloService.helloService(name);
}
/*熔断处理*/
public String helloError(String name) {
return "Hello,"+name+". Sorry,please check your network!";
}
public String defaultfallback(){
return "默认提示,太拥挤了,稍后再试...";
}
}
1.7 配置超时时间
//给需要降级的方法加上注解@HystrixCommand
//@HystrixCommand(fallbackMethod = "helloError")
@HystrixCommand(commandProperties = {
//配置超时时间
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
@RequestMapping(value = "/hello")
public String hello(@RequestParam String name){
return helloService.helloService(name);
}
1.8 服务熔断
//给需要降级的方法加上注解@HystrixCommand
//@HystrixCommand(fallbackMethod = "helloError")
@HystrixCommand(commandProperties = {
//配置超时时间
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000"),
//服务熔断配置
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60")
})
@RequestMapping(value = "/hello")
public String hello(@RequestParam String name){
return helloService.helloService(name);
}
1.9 统一设置超时时间
降级方法上加入注解@HystrixCommand.
统一设置超时时间
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 2000
1.10 单独为某个方法设置超时时间
#单独为某个方法设置超时时间:
#为hello方法设置超时时间
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 1000
#hello:表示的要配置服务降级的方法名
hello:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
2. Feign实现熔断功能
2.1 开启熔断功能
Feign是自带断路器的,在D版本的Spring Cloud之后,它没有默认打开,需要在配置文件中配置打开它,在配置文件加以下代码:
feign.hystrix.enabled=true
2.2 添加@FeignClient注解
package com.syc.cloud.service;
import com.syc.cloud.hystrix.FeignHelloServiceHystrix;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(value = "eureka-provider",fallback = FeignHelloServiceHystrix.class)
public interface FeignHelloService {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
String sayHello(@RequestParam(value = "name") String name);
}
2.3 feign熔断器处理
package com.syc.cloud.hystrix;
import com.syc.cloud.service.FeignHelloService;
import org.springframework.stereotype.Component;
/**
* feign熔断器处理
*/
@Component
public class FeignHelloServiceHystrix implements FeignHelloService {
@Override
public String sayHello(String name) {
return "Hello "+name+". Please check your network!!!";
}
}
标签:服务,17,Hystrix,SpringCloud,springframework,import,org,cloud,name From: https://blog.51cto.com/u_7044146/5965879