SpringCloud组件学习笔记系列
【SpringCloud组件学习笔记系列】(1)Eureka组件
【SpringCloud组件学习笔记系列】(2)Hystrix组件
【SpringCloud组件学习笔记系列】(3)OpenFeign组件
【SpringCloud组件学习笔记系列】(4)Gateway组件
【SpringCloud组件学习笔记系列】(5)Config组件
完整代码已在Github开源:
https://github.com/Aliang99/SpringCloud_Bill
2、SpringCloud Netflix Hystrix的使用以及讲解
Hystirx的作用主要有:服务降级、服务熔断
服务器支持的线程并发数有限,请求会一直阻塞,会导致服务器资源耗尽,从而致使所有服务都不可用,形成雪崩效应。
hystrix解决雪崩问题的手段,主要有:线程隔离、服务降级、服务熔断
hystrix会为每一个依赖服务调用分配一个小的线程池,如果线程池已满,调用将被立即拒绝。
默认不采用排队,加速失败判定时间,减少请求的等待时间。
用户的请求,将不再直接访问服务,而是通过线程池中的空闲线程来访问服务,如果线程池已满,或者请求超时,则会进行服务降级处理,服务降级可以优先保证核心服务正常运行。
用户的请求故障时,不会被阻塞,更不会无休止的等待或者看到系统崩溃,至少可以看到一个执行结果,比如友好的提示信息。
服务降级虽然会导致请求失败,但是不会导致阻塞,而且最多会影响这个依赖服务对应的线程池中的资源,对其它服务没有响应。
触发服务降级的情况分为:线程池已满、请求超时。
2.1、Hystrix的使用
2.1.1、导入依赖
在需要远程调用的服务模块中导入Hystrix依赖,即消费者微服务中。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2.1.2、添加注解
在启动类上,添加@EnableCircuitBreaker 注解,开启熔断
@SpringBootApplication
@EnableDiscoveryClient //开启Eureka客户端发现
@EnableCircuitBreaker // 开启熔断
public class SpringCloud_Consumer_80_Application {
public static void main(String[] args) {
SpringApplication.run(SpringCloud_Consumer_80_Application.class,args);
}
/**
* 创建远程调用模板对象
* @return
*/
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
2.1.3、@SpringCloudApplication注解
一般的,可以使用**@SpringCloudApplication** 注解替代以上的三个注解,即如下方式
@SpringCloudApplication // 该注解为组合注解,包含@SpringBootApplication、@EnableDiscoveryClient以及@EnableCircuitBreaker三个注解
public class SpringCloud_Consumer_80_Application {
public static void main(String[] args) {
SpringApplication.run(SpringCloud_Consumer_80_Application.class,args);
}
/**
* 创建远程调用模板对象
* @return
*/
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
2.2、编写服务降级
当目标服务的调用出现故障,我们希望快速失败,给用户一个友好的提示,因此需要提前编写好失败时的降级处理逻辑,需要用到**@HystrixCommand**来完成。
实现示例:
@RestController
@RequestMapping("consumer")
public class UserController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("queryById/{id}")
@HystrixCommand(fallbackMethod = "queryByIdFallback") // 声明服务降级的处理方法
public CommonVo<User> queryById(@PathVariable("id") Long id){
ServiceInstance serviceInstance = discoveryClient.getInstances("user-service").get(0);
String hostName = serviceInstance.getHost();
int hostPort = serviceInstance.getPort();
String url = "http://"+hostName+":"+hostPort;
CommonVo<User> resp = restTemplate.getForObject(url + "/user/queryById/" + id, CommonVo.class);
return resp;
}
//服务降级的方法,返回提示信息
public CommonVo<User> queryByIdFallback(Long id){
return new CommonVo<>(400,"抱歉,网络拥堵,请稍后再试!!!",null);
}
}
留意带有注释的地方。
@HystrixCommand(fallbackMethod = “queryByIdFallback”) // 声明服务降级的处理方法
注意:
熔断的降级逻辑方法 必须和正常逻辑方法的参数列表和返回值类型一致。
2.3、测试案例
2.3.1、启动微服务
2.3.2、访问controller
正常显示查询数据
2.3.3、停止8001
模拟请求失败的场景
2.3.4、再次访问
服务发生降级,调用了降级处理方法响应请求
2.4、默认的Fallback方法
@RestController
@RequestMapping("consumer")
@DefaultProperties(defaultFallback = "defaultFallback") //指定默认服务降级方法
public class UserController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("queryById/{id}")
//@HystrixCommand(fallbackMethod = "queryByIdFallback") // 声明服务降级的处理方法
@HystrixCommand // 指定了默认的服务降级方法,这里就不需要再指定了
public CommonVo<User> queryById(@PathVariable("id") Long id){
ServiceInstance serviceInstance = discoveryClient.getInstances("User-Service").get(0);
String hostName = serviceInstance.getHost();
int hostPort = serviceInstance.getPort();
String url = "http://"+hostName+":"+hostPort;
CommonVo<User> resp = restTemplate.getForObject(url + "/user/queryById/" + id, CommonVo.class);
return resp;
}
//服务降级的方法,返回提示信息
public CommonVo<User> queryByIdFallback(Long id){
return new CommonVo<>(400,"抱歉,网络拥堵,请稍后再试!!!",null);
}
//默认服务降级方法
public CommonVo<User> defaultFallback(){
return new CommonVo<>(400,"中国移动提醒您,你请求的服务太拥堵,请稍后再试",null);
}
}
注意:
- 在controller上添加@DefaultProperties,并指定该注解的属性defaultFallback的值为默认服务降级方法名
- 注释掉原来的//@HystrixCommand(fallbackMethod = “queryByIdFallback”) // 声明服务降级的处理方法
- 但依然需要添加 @HystrixCommand,表示该方法需要Hystrix提供服务降级功能
- 编写默认服务降级方法
- 被@DefaultProperties修饰的Controller的所有方法的返回值类型必须要与defaultFallback的返回值类型一致。参数可以不一致。
2.5、超时设置
默认情况下,请求超时1秒后,会触发服务降级,这个时间可以在配置文件中进行修改。
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 2000 # 单位是ms 默认请求超时时间是1000ms
这个值会作用于全局所有方法。
2.6、测试超时设置
2.6.1、修改配置文件
将上面的超时设置加入到consumer的配置文件中
2.6.2、修改Controller
修改consumer调用的服务型微服务的controller,模拟超时2秒的场景,让它睡两秒即可
@GetMapping("queryById/{id}")
public CommonVo<User> queryById(@PathVariable("id") Long id) {
try {
Thread.sleep(2000); //睡眠2秒
} catch (InterruptedException e) {
e.printStackTrace();
}
User user = userService.queryById(id);
if (user==null){
return new CommonVo<>(400,"数据库中暂无此数据",null);
}else{
return new CommonVo<User>(200,"OK",user);
}
}
2.6.3、启动服务
2.6.4、访问
2.7、服务熔断
在分布式系统中应用服务熔断,服务调用方可以自己进行判断哪些服务反应慢或存在大量超时,可以针对这些服务进行主动熔断,防止整个系统被拖垮。
Hystrix的熔断机制,可以实现弹性容错;当服务请求情况好转之后,自动重连。服务无法响应时,通过断路的方式,将后续请求直接拒绝,一段时间(默认5秒)后,允许部分请求通过,如果这部分请求能调用成功,则回到断路器关闭状态正常接收所有服务请求,否则继续打开,拒绝所有服务请求。
熔断器的三个状态:关闭(默认)、开启、半开
2.7.1、服务熔断器的执行过程
熔断器的执行过程:
1、默认是关闭的状态
2、当失败的请求数量达到了阈值**(请求次数20次以上,其中失败的请求达到50%以上)**,熔断器会打开,将服务降级,当前服务拒绝所有请求
3、熔断器开启5秒之后,熔断器自动变成半开状态,半开状态下,允许部分请求访问,如果能够正常访问,就进入关闭状态,如果不能,就又进入开启状态,等再过5秒,又变成半开状态,一次又一次的尝试。
4、自动打开、自动重连、自动关闭
2.7.2、测试熔断器的现象
2.7.2.1、修改consumer的controller
@RestController
@RequestMapping("consumer")
@DefaultProperties(defaultFallback = "defaultFallback") //指定默认服务降级方法
public class UserController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("queryById/{id}")
@HystrixCommand
public CommonVo<User> queryById(@PathVariable("id") Long id){
// 添加判断,每次请求参数为1 ,都抛出异常,表示请求失败
if (id == 1L){
throw new RuntimeException("太忙了"); //注意这部分
}
ServiceInstance serviceInstance = discoveryClient.getInstances("User-Service").get(0);
String hostName = serviceInstance.getHost(); // 获取主机名称
int hostPort = serviceInstance.getPort(); //获取端口
String url = "http://"+hostName+":"+hostPort; //拼接远程调用地址
CommonVo<User> resp = restTemplate.getForObject(url + "/user/queryById/" + id, CommonVo.class);
return resp;
}
//默认服务降级方法
public CommonVo<User> defaultFallback(){
return new CommonVo<>(400,"中国移动提醒您,你请求的服务太拥堵,请稍后再试",null);
}
}
2.7.2.2、重启微服务
2.7.2.3、测试请求
先将参数为1的请求,请求20次,由于测试代码中的if,会导致服务降级,失败20次,此时Hystrix便会开启熔断器
熔断器开启的5s内接着再请求相同地址,携带参数为2的请求,会发现,无法访问,也出现了服务降级
而5s后再访问,可以正常访问,因为此时熔断器已经进入了半开状态,允许部分访问。
注意:
熔断器从开启状态到半开状态这段时间默认5s。即5s后会重新连接,并等待下一次请求,如果请求能通过,则从半开状态变为关闭状态。否则又进入开启与半开的循环。
当参数为2的请求访问成功后,熔断器会进入关闭状态,此时所有请求都可以访问。
**注意:**以上测试为了模拟熔断器开启的场景,代码中写死了错误,所以再次访问参数1,依旧是无法访问的,始终抛出异常进入默认的服务降级处理。
2.7.3、服务熔断的参数
如下:
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 2000 #服务降级超时时间
circuitBreaker:
errorThresholdPercentage: 50 # 触发熔断错误比例阈值,默认值50%
sleepWindowInMilliseconds: 10000 # 熔断后休眠时长,默认值5秒
requestVolumeThreshold: 10 # 熔断触发最小请求次数,默认值是20次
参数的设置项,可以参考HystrixCommandProperties类。