前言
分布式系统中,由于多个微服务之间互相调用,这就是所谓的扇出。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,就会占用越来越多的系统资源,进而导致系统崩溃。这就是“雪崩效应”。为了处理这种情况,我们需要做服务降级、服务熔断、服务限流等处理
服务断路器
Hystrix
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败。比如超时、异常等。Hystrix能够保证在一个依赖出错的情况下,不会导致整体服务失败,避免出现级联故障,以提高分布式系统的弹性
原理
当某个服务单元发生故障的时候,通过断路器的故障监控,向服务消费方返回一个符合预期的、可处理的备选响应,而不是长时间的等待或者抛出消费方无法处理的异常,这样就保证了服务调用方的线程不会长时间、不必要的被占用,从而避免了故障在分布式系统的蔓延,引起服务雪崩
服务降级fallback
服务器忙,请稍后再试,不让客户端等待,立刻返回一个友好的提示。比如:程序运行异常、超时、服务熔断触发服务降级、线程池满等
服务熔断
请求达到最大访问后,直接拒绝访问,然后调用服务降级的方法
服务限流
秒杀等高并发操作,严禁请求一窝蜂的过来,一秒钟N个,进行排队
服务降级
服务提供方
添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--hystrix依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
业务类
@Service
//针对指定的服务,使用默认的服务降级方法,下面方法启用@HystrixCommand即可
// @DefaultProperties(defaultFallback = "timeoutFallBack")
public class PaymentServiceImpl implements PaymentService {
@Override
public String success(Integer id) {
return Thread.currentThread().getName() + "success: " + id;
}
@Override
@HystrixCommand(fallbackMethod = "timeoutFallBack", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000") // hystrix 调用超时时间
})
public String timeout(Integer id) {
// int i = 10 / 0;
int time = 2;
try {
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
return Thread.currentThread().getName() + "暂停(秒):" + time + "timeout: " + id;
}
public String timeoutFallBack(Integer id) {
return "线程:" + Thread.currentThread().getName() + "调用timeout方法出错";
}
}
主启动类添加启用Hystrix的注解@EnableCircuitBreaker
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class HystrixPaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(HystrixPaymentMain8001.class, args);
}
}
当请求访问业务类的timeout方法时,如果方法调用失败,则会进行服务降级,按照指定的降级方法timeoutFallBack进行调用,返回给预期指定结果,可以指定超时时间等,各种相关设置等
服务消费方
在feign服务消费方进行服务降低处理
添加依赖
<dependencies>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--openfeign依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.sun.cloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
修改配置文件application.yml
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
feign:
hystrix:
# 开启feign的hystrix服务
enabled: true
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 5000 #熔断超时时间
#logging:
# level:
# com.sun.cloud.service: debug
ribbon:
ReadTimeout: 60000 #请求处理的超时时间
ConnectTimeout: 60000 #请求连接超时时间
MaxAutoRetries: 0 #对当前实例的重试次数
MaxAutoRetriesNextServer: 1 #切换实例的重试次数 1
创建openfeign接口
// fallback参数指定默认的降低方法,可以将接口异常和逻辑代码分离开来
@FeignClient(value = "HYSTRIX-PAYMENT-SERVICE", fallback = PaymentFeignFallbackService.class)
public interface PaymentFeignService {
@GetMapping("/payment/success/{id}")
public String success(@PathVariable("id") Integer id);
@GetMapping("/payment/timeout/{id}")
public String timeout(@PathVariable("id") Integer id);
}
默认的降级方法
@Component
public class PaymentFeignFallbackService implements PaymentFeignService {
@Override
public String success(Integer id) {
return "我是success的fallback方法";
}
@Override
public String timeout(Integer id) {
return "我是timeout的fallback方法";
}
}
主启动类启用Hystrix
@SpringBootApplication
@EnableFeignClients
// feign中调用Hystrix使用该注解@EnableHystrix
@EnableHystrix
public class FeignHystrixOrderMain80 {
public static void main(String[] args) {
SpringApplication.run(FeignHystrixOrderMain80.class, args);
}
}
服务熔断
熔断机制的概述
熔断机制是应对雪崩效应的一种微服务链路保护机制,当扇出链路的某个微服务出错不可用或响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当服务请求书减少的时候,会自动的抽取某条请求,去重新调用,如果调用恢复正常,则恢复调用链路。
在SpringCloud框架中,使用hystrix实现服务熔断,hystrix会监控微服务的状况,当失败的调用达到某个阈值的时候,服务熔断。缺省的熔断是5秒中20次调用失败,使用@HystrixCommand注解
业务类的熔断配置
@Service
public class PaymentServiceImpl implements PaymentService {
@HystrixCommand(fallbackMethod = "timeoutFallBack", commandProperties = {
// 开启断路器
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
// 请求总数阀值,满足总阀值才有资格熔断
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
// 时间范围
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),
// 失败率多少后跳闸
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60")
})
@Override
public String circuit(Integer id) {
if(id < 0) {
throw new RuntimeException("id不能为负数");
}
String uuid = UUID.randomUUID().toString();
return uuid;
}
}
熔断的类型
- 1 熔断打开:请求不在调用当前服务,内部设置一般为MTTR(平均故障处理时间),当打开长达导所设时钟则进入半熔断状态
- 2 熔断关闭:熔断关闭后不会对服务进行熔断
- 3 熔断半开:部分请求根据规则调用当前服务,如果请求成功且符合规则则认为当前服务恢复正常,关闭熔断
Hystrix DashBoard仪表盘
除了隔离依赖服务的调用之外,Hystrix提供准实时的调用监控,Hystrix DashBoard会持续的记录通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少次成功、失败等。
添加依赖
<dependencies>
<!--hystrix dashboard-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<!--监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
配置文件的修改
server:
port: 9001
主启动类
@SpringBootApplication
// 启用HystrixDashboard
@EnableHystrixDashboard
public class HystrixDashboardMain9001 {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardMain9001.class, args);
}
}
注意点
所有需要监听的服务都需要添加如下依赖:
<!--监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
在服务提供端主启动类添加监听路径
/**
* 此配置是为了服务监控而配置,与服务容错本身无观,springCloud 升级之后的坑
* ServletRegistrationBean因为springboot的默认路径不是/hystrix.stream
* 只要在自己的项目中配置上下面的servlet即可
* @return
*/
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
访问地址:http://localhost:9001/hystrix
监听地址:http://localhost:8001/hystrix.stream