springCloud初识3-熔断Hystrix
Hystrix(豪猪),全身是刺,是一种保护机制。Hystrix也是Netflix公司的一款组件。
雪崩问题
微服务中,服务间调用关系错综复杂,一个请求,可能需要调用多个微服务接口才能实现,会形成非常复杂的调用链路。
服务器支持的线程和并发数有限,请求一直阻塞,会导致服务器资源耗尽,从而导致所有其它服务都不可用,形成雪崩效应。
这就好比,一个汽车生产线,生产不同的汽车,需要使用不同的零件,如果某个零件因为种种原因无法使用,那么就会造成整台车无法装配,陷入等待零件的状态,直到零件到位,才能继续组装。
此时如果有很多个车型都需要这个零件,那么整个工厂都将陷入等待的状态,导致所有生产都陷入瘫痪。一个零件的波及范围不断扩大。
Hystix解决雪崩问题的手段有两个:
- 线程隔离
- 服务熔断
线程隔离
Hystrix为每个依赖服务调用分配一个小的线程池, 如果线程池已满调用将被立即拒绝,默认不采用排队,加速失败判定时间。
用户的请求将不再直接访问服务,而是通过线程池中的空闲线程来访问服务,如果线程池已满,或者请求超时,则会进行降级处理,什么是服务降级?
服务降级:
优先保证核心服务,而非核心服务不可用或弱可用。
用户的请求故障时,不会被阻塞,更不会无休止的等待或者看到系统崩溃,至少可以看到一个执行结果(例如返回友好的提示信息)。
服务降级虽然会导致请求失败,但是不会导致阻塞,而且最多会影响这个依赖服务对应的线程池中的资源,对其它服务没有影响。
触发Hystix服务降级的情况:
- 线程池已满
- 请求超时
服务熔断
hystrix服务降级
实例
1--引入依赖(消费端服务)
<dependency>
groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2--覆盖默认配置
可不做任何配置,直接使用默认配置
3--引导类启用组件(消费端服务)
package com.xiaoai.service;
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.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient //启用eureka客户端,@EnableEurekaClient也可以
@EnableCircuitBreaker //开启熔断
public class XiaoaiServiceConsumerApplication {
@Bean
@LoadBalanced //开启负载均衡
public RestTemplate restTemplate(){return new RestTemplate();}
public static void main(String[] args) {SpringApplication.run(XiaoaiServiceConsumerApplication.class, args);}
}
4--控制类编写熔断方法并关联 如:
package com.xiaoai.service.controller;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.xiaoai.service.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
@RequestMapping("/consumer/user")
public class UserController {
//-----------------------------------------------改造消费方,解决地址硬编码问题 启用ribbon负载均衡后
@Autowired
private RestTemplate restTemplate;
@GetMapping
@ResponseBody
@HystrixCommand(fallbackMethod = "queryUserByIdFalback") //2--关联熔断方法
public String queryUserById(@RequestParam("id")Long id){
return this.restTemplate.getForObject("http://service-provider/user/"+id,String.class);
}
//1--定义熔断方法
public String queryUserByIdFalback(Long id){
return "服务器正忙,请稍后再试!";
}
}
关闭提供服务访问相应消费服务端url可见:
定义全局熔断方法
package com.xiaoai.service.controller;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/consumer/user")
@DefaultProperties(defaultFallback = "FalbackMethod") // 定义全局熔断方法
public class UserController {
//-----------------------------------------------改造消费方,解决地址硬编码问题 启用ribbon负载均衡后
@Autowired
private RestTemplate restTemplate;
@GetMapping
@ResponseBody
@HystrixCommand //声明熔断方法。使用全局默认方法,属性fallbackMethod = "queryUserByIdFalback"可以不用了,但注解还是要。
public String queryUserById(@RequestParam("id")Long id){
return this.restTemplate.getForObject("http://service-provider/user/"+id,String.class);
}
//定义熔断方法
public String queryUserByIdFalback(Long id){ //熔断方法返回值必须和控制方法返回值一样
return "queryUserByIdFalback熔断:服务器正忙,请稍后再试!";
}
//熔断方法
public String FalbackMethod(){
return "全局熔断:服务器正忙,请稍后再试!";
}
}
关闭提供服务访问相应消费服务端url可见:
小结
- 引入hystrix启动器
- application配置文件配置熔断时间,默认1秒
- 引导类注解:@EnableCircuitBreaker、@SpringCloudApplication
- 定义熔断方法
- 局部熔断方法:要和被熔断的控制器方法返回值及参数列表一致
- 全局熔断方法:返回值类型要和被熔断的控制器方法一致,参数列表必须为空
- 方法上@HystrixCommand:通过属性fallbackMethod="局部熔断方法名"声明被熔断的方法,不声明默认使用全局熔断方法
- 类上@DefaultProperties: 通过属性defalutFallback="全局熔断方法名" 声明全局熔断方法
设置超时
当发生熔断,请求在超过1秒后就会返回错误信息,这是因为Hystix的默认超时时长为1,我们可以通过配置消费端服务application.yml配置文件修改这个值:
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 6000 #设置hys trix的超时时间为6000ms
组合注解@SpringCloudApplication
package com.xiaoai.service;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
//@SpringBootApplication //标注该类为springboot的引导类
//@EnableDiscoveryClient //启用eureka客户端,@EnableEurekaClient也可以
//@EnableCircuitBreaker //开启熔断
@SpringCloudApplication //组合注解 相当于@SpringBootApplication、@EnableDiscoveryClient 、@EnableCircuitBreaker
public class XiaoaiServiceConsumerApplication {
@Bean
@LoadBalanced //开启负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(XiaoaiServiceConsumerApplication.class, args);
}
}
hystrix熔断 连请求都不发
熔断机制的原理很简单,像家里的电路熔断器,如果电路发生短路能立刻熔断电路,避免发生灾难。在分布式系统中应用这一模式之后, 服务调用方可以自己进行判断某些服务反应慢或者存在大量超时的情况时,能够主动熔断,防止整个系统被拖垮。
不同于电路熔断只能断不能自动重连,Hystrix 可以实现弹性容错,当情况好转之后,可以自动重连。通过断路的方式,可以将后续请求直接拒绝掉,一段时间之后允许部分请求通过,如果调用成功则回到电路闭合状态,否则继续断开。
熔断状态机3个状态
- Closed:关闭状态,所有请求都正常访问。
- Open:打开状态,所有请求都会被降级。Hystix会对请求情况计数, 当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全打开。默认失败比例的阈值是50%,请求次数最少不低于20次。
- Half Open:半开状态,open状态不是永久的,打开后会进入休眠时间(默认是5S)。随后断路器会自动进入半开状态。此时会释放部分请求通过,若这些请求都是健康的,则会完全关闭断路器,否则继续保持打开,再次进行休眠计时
实例
1--消费服务端控制器方法(人为制造异常)
package com.xiaoai.service.controller;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/consumer/user")
@DefaultProperties(defaultFallback = "FalbackMethod") // 定义全局熔断方法
public class UserController {
//-----------------------------------------------改造消费方,解决地址硬编码问题 启用ribbon负载均衡后
@Autowired
private RestTemplate restTemplate;
@GetMapping
@ResponseBody
@HystrixCommand //声明熔断方法。使用全局默认方法,属性fallbackMethod = "queryUserByIdFalback"可以不用了,但注解还是要。
public String queryUserById(@RequestParam("id")Long id){
if (id==1){
throw new RuntimeException();
}
return this.restTemplate.getForObject("http://service-provider/user/"+id,String.class);
}
//熔断方法
public String queryUserByIdFalback(Long id){ //熔断方法返回值必须和控制方法返回值一样
return "queryUserByIdFalback熔断:服务器正忙,请稍后再试!";
}
//熔断方法
public String FalbackMethod(){
return "全局熔断:服务器正忙,请稍后再试!";
}
}
即:上述代码默认情况下id=1访问会被熔断,id=2正常,当连续快速访问id=1后,马上访问id=2,此时id=2也会被熔断
默认的熔断触发要求较高,休眠时间窗较短,为了测试方便,我们可以通过在消费服务端application配置文件配置修改熔断策略:
- circuitBreaker.requestVolumeThreshold=10
- circuitBreaker.sleepwindowInMillis econds=10000
- circuitBreaker.errorThresholdPer centage=50
requestVolumeThreshold: 触发熔断的最小请求次数,默认20
errorThresholdPercentage: 触发熔断的失败请求最小占比,默认50%
sleepWindowInMilliseconds: 休眠时长,默认是5000毫秒