上一章我们讲了负载均衡
文章目录
- 前言
- 一、Hystrix是什么?
- 二、Hystrix的作用是什么?Hystrix具体要保护什么?
- 2.1什么是微服务-雪崩效应
- 2.1服务熔断原理
- 三、实践
前言
一、Hystrix是什么?
有意思的是Hystrix在英文里面是豪猪的意思,手册上这个图笑死我了,这个分明是熊,哪会是猪,变种猪么?
仔细看图,会发现这是满身的刺,不管是熊是猪,给人感觉伪装成了刺猬。一眼看过去很容易理解,满身刺和伪装目的是保护自己的作用。因此从图中就可以看出它在微服务中是一款提供保护机制的组件。
二、Hystrix的作用是什么?Hystrix具体要保护什么?
Hystrix是Netflix开源的一个延迟和容错库,用于隔离访问远程服务和第三方库级联故障。也就是说Hystrix是一个库,可以做什么?防止出现级联失败。
2.1什么是微服务-雪崩效应
微服务中,服务关系调用,错综复杂,一个请求可能需要调用多个服务接口才能实现,会形成非常复杂的调用链路。
假设 我们有两个访问量比较大的服务A和B,这两个服务分别依赖C和D,C和D服务都依赖E服务
所有服务正常提供服务的情况下,请求顺利被处理完,后面的请求一样被处理。
A和B不断的调用C,D处理客户请求和返回需要的数据。当E服务出现故障,Tomcat不会释放线程,C和D的超时和重试机制又会被执行。后面又不断有新的请求进来,形成阻塞。而服务器支持的线程和并发数又有限,请求一直阻塞,那么会导致服务器资源耗尽。导致服务E直接GG
由于新的调用不断的产生,会导致C和D对E服务的调用大量的积压,产生大量的调用等待和重试调用,慢慢会耗尽C和D的资源如内存或CPU,然后也down掉。
A和B服务会重复C和D的操作,资源耗尽,然后down掉,最终整个服务都不可访问。
那么Hystrix如何解决这个雪崩的问题呢?主要是通过服务降级的方式,包括线程隔离,服务熔断。
2.1服务熔断原理
在服务熔断中使用的熔断器,也叫断路器Circuit Breaker
熔断器与家里使用的电路断路器原理类似;当电路发生短路的时候能够立刻熔断,避免灾难发生。在分布式系统中应用服务熔断之后;服务调用方可以自己判断哪些服务反应慢或者存在大量超时,可以针对这些服务进行主动熔断,防止整个系统被拖垮。
Hystrix的服务熔断机制,可以实现弹性容错;当服务请求情况好转之后;可以自动重连。通过短路的方式,将后续的请求直接拒绝,一段时间(一般是5秒)之后允许部分请求通过,如果调用成功则回到短路器关闭状态,否则继续打开,拒绝请求服务。
三个状态:
Closed: 关闭状态(断路器关闭),所有请求都正常访问。
Open: 打开状态(断路器打开),所有服务都会被降级,断路器关闭时Hystrix会对请求情况计数,当一定时间内请求百分比达到阀值,则触发熔断,断路器会完全打开。默认的失败比例阀值是50%,请求次数最少不低于20次。
Half Open: 半开状态,不是永久的,断路器完全打开之后会进入休眠时间(默认是秒)。随后断路器会自动进入半开状态,此时通过释放部分请求通过,若这些请求都是健康的,则关闭断路器,否则保持打开,再次进入休眠计时。
三、实践
老样子,先拿到上一章的工程继续修改 上一章工程
我们要用Hystrix,当然是需要引入包了,因此我们需要在custom-demo工程pom中引入。
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
随后要在custom-demo工程的handler层UserHandler添加一个异常时跳转的方法。
@RestController
@RequestMapping("user")
@DefaultProperties(defaultFallback = "defaultFallback")
public class UserHandler {
@Autowired
private RestTemplate restTemplate;
@Autowired
private UserService userService;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/{id}")
@HystrixCommand
public String doGet(@PathVariable Long id){
// String url = "http://127.0.0.1:1001/user/"+id;
// return "<div><h1>custom-Service回应:</h1><div>"+restTemplate.getForObject(url, String.class);
// return userService.doGetUser(id);
// List<ServiceInstance> serviceInstances= discoveryClient.getInstances("user-service");
// String url = "http://"+serviceInstances.get(0).getHost()+":"+serviceInstances.get(0).getPort()+"/user/"+id;
/**
* 模拟id=1时目标服务器异常。
*/
if(1==id){
throw new RuntimeException("要访问的服务器异常");
}
String url = "http://user-service/user/"+id;
return "<div><h1>custom-Service[通过注册中心拉取服务]回应:</h1><div>"+restTemplate.getForObject(url, String.class);
}
/**
* 检测到doGet异常时,会跳到这里来
* @return
*/
public String defaultFallback(){
return "默认提示:要访问的服务器异常!";
}
}
启动类加上@EnableCircuitBreaker注解,打开熔断器。
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class CustomService {
public static void main(String[] args) {
SpringApplication.run(CustomService.class, args);
}
@Bean
@LoadBalanced //负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
随后可以运行eureka、user-service、custom-demo三个工程,启动好之后访问
http://localhost:9001/user/1
二十次以上,这样就会打开断路器
此时再访问
http://localhost:9001/user/2
就会看到
过一会儿再次访问
http://localhost:9001/user/2
会发现此时断路器已经自动关闭
以上的案例使用的是默认值,再yml可以不用配置,也可以如下配置,有兴趣,您可以修改参数查看效果
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 1000 #触发服务降级的时间,默认时1000ms
circuitBreaker:
errorThresholdPercentage: 50 #触发熔断比例阈值,默认值50%
sleepWindowInMillisecconds: 100000 #熔断后休眠时长,默认5秒
requestVolumeThreshold: 20 #熔断触发最小请求次数,默认值20
本章例程
那么本章到这就先结束了,下一章介绍一下Feign。