1.服务雪崩
2、Hystrix介绍
- Hystrix 是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix 能够保证在一个依赖出问题的 情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
- “断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应 (FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延, 乃至雪崩。
- Hytrix 能够提供服务降级、服务熔断、服务限流、接近实时的监控等方面的功能。
3、服务熔断机制 - 熔断机制是应对雪崩效应的一种微服务链路保护机制。 当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该 节点微服务的调用,快速响应错误信息。当检测到该节点微服务调用响应正常后恢复调用链 路。在 SpringCloud 框架里熔断机制通过 Hystrix 实现。Hystrix 会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是 5 秒内 20 次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand。
4.熔断-代码部分
熔断指的是provider方的熔断,如果provider方出现的问题,熔断后别的就不在调用这个方法。
1. 在provider工程中添加依赖
2. 在provider主启动类上添加 @EnableCircuitBreaker 注解<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
3. 在common 工程中添加一个 ResultEntity ,统一作为AJAX请求和远程服务调用返回值/** * @date: * @author: * 下面两个注解功能大致相同,但是这个版本不需要添加 * @EnableDiscoveryClient: 启用发现服务功能,不局限于Eureka注册中心 * @EnableEurekaClient: 启用Eureka客户端功能,必须是Eureka注册中心 * * @EnableCircuitBreaker: 启用断路器功能【服务熔断】 */ @EnableCircuitBreaker @SpringBootApplication public class ApplicationProvider { public static void main(String[] args) { SpringApplication.run(ApplicationProvider.class); } }
package com.atguigu.spring.cloud.util; /** * 整个项目统一使用这个类型作为Ajax请求或远程方法调用返回响应的数据格式 * @author * * @param <T> */ public class ResultEntity<T> { public static final String SUCCESS = "SUCCESS"; public static final String FAILED = "FAILED"; public static final String NO_MESSAGE = "NO_MESSAGE"; public static final String NO_DATA = "NO_DATA"; /** * 操作成功,不需要返回数据 * @return */ public static ResultEntity<String> successWithoutData() { return new ResultEntity<String>(SUCCESS, NO_MESSAGE, NO_DATA); } /** * 操作成功,需要返回数据 * @param data * @return */ public static <E> ResultEntity<E> successWithData(E data) { return new ResultEntity<>(SUCCESS, NO_MESSAGE, data); } /** * 操作失败,返回错误消息 * @param message * @return */ public static <E> ResultEntity<E> failed(String message) { return new ResultEntity<>(FAILED, message, null); } private String result; private String message; private T data; public ResultEntity() { } public ResultEntity(String result, String message, T data) { super(); this.result = result; this.message = message; this.data = data; } @Override public String toString() { return "ResultEntity [result=" + result + ", message=" + message + ", data=" + data + "]"; } public String getResult() { return result; } public void setResult(String result) { this.result = result; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public T getData() { return data; } public void setData(T data) { this.data = data; } }
4. provider工程中的controller方法
/** * @HystrixCommand 注解通过 fallbackMethod属性指定断路情况下要调用的备用方法 * @param name * @return */ @HystrixCommand(fallbackMethod= "getUserBackUp") @RequestMapping("/provider/get/user") public ResultEntity<User> getUser(@RequestParam String name){ // 如果这个方法出现 错误/超时 就会去调用备用方法 【超时默认为1秒】 return ResultEntity.successWithData(new User(1,"aaa","男")); } /** * 备选方案 * @param name * @return */ public ResultEntity<User> getUserBackUp(@RequestParam String name){ return ResultEntity.failed("熔断机制触发!"); }
/** * 超时访问,设置自身调用超时的峰值,峰值内正常运行,超过了峰值需要服务降级 自动调用fallbackMethod 指定的方法 * 超时异常或者运行异常 都会进行服务降级 * 设置3秒钟,3秒钟内正常运行,超过了3秒钟执行fallbackMethod 的方法 * @param id * @return */ @HystrixCommand(fallbackMethod = "paymentInfoTimeOutHandler", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") }) public String paymentInfoTimeOut(Integer id) { // int age = 10/0; //运行报错一进来就执行fallbackMethod 的方法 int second = 5; long start = System.currentTimeMillis(); try { TimeUnit.SECONDS.sleep(second); } catch (InterruptedException e) { e.printStackTrace(); } long end = System.currentTimeMillis(); System.out.println(end - start); return "线程池: " + Thread.currentThread().getName() + " paymentInfoTimeOut,id: " + id + "\t" + "O(∩_∩)O哈哈~" + " 耗时(秒): " + second; } /** * paymentInfoTimeOut 方法失败后 自动调用此方法 实现服务降级 告知调用者 paymentInfoTimeOut 目前无法正常调用 * * @param id * @return */ public String paymentInfoTimeOutHandler(Integer id) { return "线程池: " + Thread.currentThread().getName() + " paymentInfoTimeOutHandler8001系统繁忙或者运行报错,请稍后再试,id: " + id + "\t" + "o(╥﹏╥)o"; }
5.注意: - 这只是熔断部分,没有远程调用,所以不用在common的service中写同名接口
- 浏览器访问的时候直接访问provider的controller【测试】
5.服务的降级
整体资源快不够了,忍痛将某些服务先关掉,待渡过难关,再开启回来
- 当某个Consumer访问一个provider却迟迟得不到响应时预先设定好一个解决方案,而不是一直等待。
5.1.common工程添加 Hystrix依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
5.2. common工程中需要定义一个工厂类
实现 FallbackFactory 接口【泛型为Common中的远程调用Service】
/**
* 1.实现Consumer端服务降级的功能
* 2.实现FallbackFactory接口时要传入@FeignClient接口类型
* 3.在create()方法中返回一个@FeignClient注解标注的接口类型的对象,当Provider调用失败后,会执行这个对象的对应方法
*/
@Component
public class MyFallBackFactory implements FallbackFactory<UserRemoteService> {
@Override
public UserRemoteService create(Throwable throwable) {
return new UserRemoteService() {
@Override
public ResultEntity<User> getUser(String name) {
return ResultEntity.failed("consumer端降级!!");
}
};
}
}
3. 修改common的远程 调用接口
common工程中原来的远程调用接口 UserRemoteService 的@FeignClients要添加 FallbackFactory属性为自己写的工厂.class ,fallbackFactory属性指定provider不可用时提供备用方案的工厂对象
4.feign-consumer端启动hystrix
【在配置文件中启动】
feign:
hystrix:
enabled: true
主启动类上:
@SpringBootApplication
@EnableFeignClients // 启动 feign
@EnableHystrix // 启动 hystrix
public class CloudConsumerFeignHystrixOrder80Application {
public static void main(String[] args) {
SpringApplication.run(CloudConsumerFeignHystrixOrder80Application.class, args);
System.out.println("启动成功");
}
}
消费端也有服务降级,如果超时和报错,一样是执行fallbackMethod里的方法
@GetMapping("/payment/hystrix/timeout/{id}")
@HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")
})
@HystrixCommand
public String paymentInfoTimeOut(@PathVariable("id") Integer id) {
int age = 10 / 0;
String result = paymentHystrixService.paymentInfoTimeOut(id);
return result;
}
/**
* 超时访问,设置自身调用超时的峰值,峰值内正常运行,超过了峰值需要服务降级 自动调用fallbackMethod 指定的方法
* <br/>
* 超时异常或者运行异常 都会进行服务降级
*
* @param id
* @return
*/
public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
return "我是消费者80,对方支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
}
还有hystrix监控,看这篇文章:hystrixDashboard(服务监控) - 风止雨歇 - 博客园