目录
一. Hystrix 基础概述
-
Hystrix 是一个用来处理分布式系统的延迟和容错的开源库,例如在分布式环境下,服务与服务之间相互依赖不可避免出现调用失败问题,超时,异常等等,通过 Hystrix 保证一个服务出现问题时不影响其他服务,避免级联故障,提高分布式系统的弹性
-
Hystrix 主要作用: 服务降级, 服务熔断, 提供接近实时的监控
-
服务降级: 当服务不可用时(例如服务等待,服务报错等等)返回一个错误提示给用户,用户不用继续等待,提供用户体验,使用fallback返回当前服务不可用的提示,服务熔断与服务降级一般会一块使用,当拒绝请求后给出提示,例如请稍后再试(适用于高并发,防止服务器的血崩效应,服务器挂掉)
-
服务熔断: 设置一个限制,当服务请求超过限制时,拒绝请求,调用服务降级方法给用户提示信息, ,比如最多只能同时访问100个请求,超出请求放入缓存队列中,队列已满时,拒绝访问,并且调用链路会有一个自动恢复过程,在恢复期内请求正常了可能还是会走降级方法,要等到关闭熔断
-
服务隔离: 通过服务熔断降级,实现服务隔离的效果,服务与服务
-
服务限流: 防止恶意请求工具,服务限流,服务熔断,服务降级,放到一块是一条顺序性的执行流程
-
Hystrix 降级熔断底层可以通过线程池或信号量两种方式来实现,可以通过编码或注解两种方式来进行具体实现
二. Hystrix 服务降级
- 服务降级,可以简单理解为调用的方法响应超时,发生异常,设置请求执行一个备用的方法,返回一个友好提示,而不是超时时同步等待,报错时直接返回错误
- Hystrix 可以用在服务提供方,也可以用在服务消费方,但是与 Feign 客户端服务调用配合使用时需要在yml文件中配置开启 Feign 客户端的 Hystrix 功能
- 实现步骤
- 项目中引入 Hystrix 依赖
- 项目启动类添加 @EnableHystrix 修饰开启 Hystrix
- 设置指定需要降级处理的方法,提供降级方法
- 服务消费方调用服务提供方降级时 yml 文件中配置开启 Feign 客户端的 Hystrix 功能
服务消费方注解方式降级配置示例
- pom 文件中引入 Hystrix 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
- yml 文件中配置开启 Feign 客户端支持 Hystrix ,feign: hystrix: enabled: true
server:
port: 80 #当前服务端口号
spring:
application:
name: cloud-feign-hystix-order-service #当前服务名称
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
#eureka 注册中心访问连接,集群环境多个注册地址
defaultZone: http://127.0.0.1:7001/eureka,http://127.0.0.1:7002/eureka
instance:
instance-id: order80 #配置当前服务向eureka注册中心注册时显示的服务器主机名称
prefer-ip-address: true #配置在开发人员直接访问eureka服务器时显示当前eureka上注册的服务的ip
lease-renewal-interval-in-seconds: 1 #指定定时向eureka注册中心发送代表当前服务心跳包的时间默认30秒
lease-expiration-duration-in-seconds: 2 # Eureka 接收到当前服务最后一次发送代表正常心跳包的等待时间,超过则将当前服务在 Eureka 上踢除
#=====================Feign===========================================
#开启 Feign 接口调用 Hystrix功能
feign:
hystrix:
enabled: true
#超时时间配置
ribbon:
ReadTimeout: 5000 #当前服务消费方调用服务提供方,建立连接超时时间,默认1秒超过报错
ConnectTimeout: 5000 #当前服务消费方与服务提供方建立连接后调用服务接口读取资源的时间
#配置 Feign 日志功能
logging:
level:
#表示 com.order.feignService.PaymentFeignService 接口中的方法执行,被 Feign 监控,记录日志
com.order.feignService.PaymentFeignService: debug
#=====================Feign end===========================================
- 启动类 @EnableHystrix 开启 Hystrix
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
@EnableHystrix //开启Hystrix
public class OrderFeignHystixMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderFeignHystixMain80.class,args);
}
}
@DefaultProperties(defaultFallback = “降级方法名称”) + @HystrixCommand 对多个方法提供相同的默认降级方法
-
@DefaultProperties(defaultFallback = “降级方法名称”) 注解用来修饰类, defaultFallback 属性值设置为指定的降级方法
-
@HystrixCommand 修饰该类中需要进行降级处理的方法,当该类中被该注解修饰的方法执行时,触发降级条件会自动执行 defaultFallback 中指定的方法
-
该方式存在的缺点: 不能对指定方法进行指定降级处理,并且降级方法的入参出参要与实际的方法一一对应,否则可能会报错找不到该降级方法
-
代码示例: 该方法中的 getException() 方法或 getException2() 方法执行报错会执行降级方法 defaultFallBack()
import com.common.result.JsonResult;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.order.feignServer.PaymentFeignServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping(value = "/consumer")
@DefaultProperties(defaultFallback = "defaultFallBack")
public class OrderController {
@Autowired
private PaymentFeignServer paymentFeignServer;
@GetMapping(value = "/getException")
@HystrixCommand
public JsonResult getException(){
return paymentFeignServer.getException();
}
@GetMapping(value = "/getException2")
@HystrixCommand
public JsonResult getException2(){
int i =1/0;
return paymentFeignServer.getException();
}
public JsonResult defaultFallBack(){
return JsonResult.successResult("默认的降级方法执行");
}
}
- @DefaultProperties 类级别降级,熔断微调
@DefaultProperties( defaultFallback = "defaultFallBack"
commandProperties={
// 请求必须达到以下参数以上才有可能触发,也就是10秒內发生连续调用的最小参数
@HystrixProperty(name="circuitBreaker.requestVolumeThreshold", value="10"),
// 请求到达requestVolumeThreshold 上限以后,调用失败的请求百分比
@HystrixProperty(name="circuitBreaker.errorThresholdPercentage", value="75")}
)
@HystrixCommand 注解修饰对指定方法进行指定降级配置
- @HystrixCommand 修饰方法,通过该注解的 fallbackMethod 属性与 commandProperties 属性对被修饰的方法进行指定的降级处理
- 与 @DefaultProperties 同时存在时有优先级,会使用 @HystrixCommand 中的设置
- 代码示例: 此时当 hystixGetValTimeout() 方法执行时,如果报错,或4000毫秒内没有返回结果会执行fallbackMethod 属性指定的降级方法 fallBack ()
@GetMapping(value = "/timeout")
@HystrixCommand(fallbackMethod ="fallBack", commandProperties = {
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value = "4000")
})
public JsonResult hystixGetValTimeout(){
return paymentFeignServer.hystixGetValTimeout();
}
public JsonResult fallBack(){
return JsonResult.successResult("指定的降级方法执行");
}
- @HystrixCommand 异常忽略,当被该注解修饰的方法抛出 ignoreExceptions 属性指定的异常时,不会执行回调方法
@HystrixCommand(ignoreExceptions = {RuntimeException.class},
fallbackMethod = "buildFallbackTestException")
@FeignClient 针对服务调用进行降级配置
- 使用 Feign 客户端进行 SpringCloud 微服务调用时,会创建一个接口,使用 @FeignClient 注解修饰该接口,通过注解上的value值指定调用哪个服务提供方的服务接口,凡是value指定的服务下的接口都在此处编写一一对应的抽象方法,调用时通过该接口调用
- 观察上面使用 @HystrixCommand 对指定方法进行降级设置,存在的问题: 业务代码与熔断代码耦合到一块不好管理
- 创建一个专门的降级类,该类继承 Feign 服务调用的接口,重写接口中的所有方法,对每个调用消费服务的方法都提供一个降级处理的方法,并且注入到 Spring 容器中
- @FeignClient 注解中有 fallback 属性,设置该属性值为继承被修饰接口的降级类,当接口中的方法触发降级时自动执行降级类中重写的降级方法
- 代码示例
- 向注册中心获取服务提供方地址,调用服务提供方接口进行消费的 Feign 接口
import com.common.result.JsonResult;
import com.order.fallback.PaymentFallBackService;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.concurrent.TimeUnit;
//该接口表示:在注册中心获取名为"CLOUD-PROVIDER-HYSTIX-PAYMENT" 的服务提供方的调用地址
//本地Ribbon 负载后可以调用该服务中请求路径为"/getValOk","/timeout","/getException" 的方法
//并且通过 fallback 属性指定降级类为 PaymentFallBackService, 该类继承了该接口,重写该接口中
//的所有抽象方法,就是对应调用服务时触发降级自动执行的降级方法
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTIX-PAYMENT", fallback = PaymentFallBackService.class)
public interface PaymentFeignServer {
@RequestMapping(value = "/getValOk", method = RequestMethod.GET)
public JsonResult hystixGetValOk();
@RequestMapping(value = "/timeout", method = RequestMethod.GET)
public JsonResult hystixGetValTimeout();
@RequestMapping(value = "/getException", method = RequestMethod.GET)
public JsonResult getException();
}
- 创建继承 Feign 接口的降级类 PaymentFallBackService,并注入到 Spring 容器中
import com.common.result.JsonResult;
import com.order.feignServer.PaymentFeignServer;
import org.springframework.stereotype.Component;
@Component
public class PaymentFallBackService implements PaymentFeignServer {
@Override
public JsonResult hystixGetValOk() {
return JsonResult.successResult("执行 /getValOk 请求异常 fallBack 降级");
}
@Override
public JsonResult hystixGetValTimeout() {
return JsonResult.successResult("执行 /timeout 请求异常 fallBack 降级");
}
@Override
public JsonResult getException() {
return JsonResult.successResult("执行 /getException 请求异常 fallBack 降级");
}
}
三. @HystrixProperty
//设置隔离策略"THREAD"为线程池方式(默认),"SEMAPHORE"为信号量方式
@HystrixProperty(name="execution.isolation.strategy",value="THREAD"),
//线程池方式设置线程微调
@HystrixProperty(name = "coreSize",value="30"),
@HystrixProperty(name="maxQueueSize", value="10")},
//当隔离策略为信号量方式时,设置最大并发数量
@HystrixProperty(name="execution.isolation.semaphore.maxConcurrentRequests",value = "10"),
//是否开启超时时间
@HystrixProperty(name="execution.timeout.enabled",value="true"),
//方法调用超时时间
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value = "3000"),
//执行超时时是否中断
@HystrixProperty(name = "execution.isolation.thread.interruptOnTimeout",value = "true"),
//执行被取消时候是否中断
@HystrixProperty(name = "execution.isolation.thread.interruptOnCancel",value = "true"),
//设置回调降级方法执行的最大并发数
@HystrixProperty(name = "fallback.isolation.semaphore.maxConcurrentRequests",value = "10"),
//服务降级是否启动,是否执行回到函数
@HystrixProperty(name = "fallback.enabled",value = "true"),
@HystrixProperty(name="circuitBreaker.forceOpen",value = "false"),//强制开启断路器
@HystrixProperty(name="circuitBreaker.enabled", value = "true"), //是否开启断路器
@HystrixProperty(name="circuitBreaker.requestVolumeThreshold", value="20"),//请求次数
@HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds", value="10000"),//时间窗口期
@HystrixProperty(name="circuitBreaker.errorThresholdPercentage", value = "50")//失败率达到多少跳闸