断路器是为了解决微服务中服务异常情况时的时返回预期提示的方解决方案。
服务降级 服务熔断 服务限流 是断路器的三个基本概念
出现服务降级的原因:
服务不可用
超时
服务熔断触发降级
信号量/线程池打满导致降级
服务熔断: 类似保险 达到最大服务访问量后 直接拒绝访问
服务限流: 秒杀等高并发操作 严禁一次性请求过多,没秒N个,有序进行
有了对hystrix基本了解,上代码
首先构建服务提供方代码
新建模块cloud-hystrix-provider8001
导入以下pom 比之前的提供方多了hystrix依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud2021</artifactId> <groupId>com.liuxu</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-hystrix-provider8001</artifactId> <dependencies> <!--引入comm工程--> <dependency> <groupId>com.liuxu</groupId> <artifactId>cloud-commons</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--eurekaClient--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--hystrix断路器--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <!--springboot 必须有的--> <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> </dependency> </dependencies> </project>
主启动类
package com.liuxu; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; /** * @author liuxu * @date 2021/10/30 20:15 */ @SpringBootApplication @EnableEurekaClient public class HystrixProvider8001 { public static void main(String[] args) { SpringApplication.run(HystrixProvider8001.class,args); } }
controller 模拟正常 和耗时返回 两种情况的调用情况
package com.liuxu.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.TimeUnit; /** * @author liuxu * @date 2021/10/30 20:17 */ @RestController @RequestMapping("hystrix/") public class PayController { @Value("${server.port}") String port; @RequestMapping("/ok") public String paymentinfo_ok(){ return "端口"+port+ "hystrix 提供者正常返回,线程是:"+Thread.currentThread().getName(); } @RequestMapping("/err") public String paymentinfo_err(){ try{ TimeUnit.SECONDS.sleep(3); }catch (Exception e){ e.printStackTrace(); } return "端口"+port+"hystrix 提供者超时返回,线程是:"+Thread.currentThread().getName(); } }
yml配置
需要将服务注册到注册中心 7001 (当然hystrix使用不是和注册中心有必然联系,在简单的springboot项目中也能用,这里是为了之后可以作为服务提供者被其他服务调用)
server: port: 8001 #端口号 spring: application: name: cloud-hystrix-provider #服务名 eureka: client: # 是否从Eureka抓取注册信息 单节点情况下无用 集群情况下才能配合robbion使用负载均衡 fetch-registry: true # 注册如Eureka 用 true register-with-eureka: true service-url: # 设置与eureka server交互的地址查询和注册服务都需要这个地址 向注册中心注册 defaultZone: http://localhost:7001/eureka/
启动注册中心7001 启动hystrix提供方服务 8001,访问
http://localhost:8001/hystrix/ok 正常很快返回
http://localhost:8001/hystrix/err 一段时间(3s)返回
以上看上去都很正常
这时候我们使用jmeter压力测试工具给
http://localhost:8001/hystrix/err每秒发送200000个请求
你会发现
http://localhost:8001/hystrix/err
http://localhost:8001/hystrix/ok 都会出现卡顿
如果这时候有服务调用8001接口,就会出现服务等待,超时现象
下面构建cloud-hytrix-consumer-81服务来验证
pom中主要添加 OpenFeign hystrix
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud2021</artifactId> <groupId>com.liuxu</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-hytrix-consumer-81</artifactId> <dependencies> <!--引入comm工程--> <dependency> <groupId>com.liuxu</groupId> <artifactId>cloud-commons</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--eurekaClient--> <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> <!--hystrix--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <!--springboot 必须有的--> <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> </dependency> </dependencies> </project>
主启动类
package com.liuxu; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; /** * @author liuxu * @date 2021/10/27 21:45 */ @SpringBootApplication @EnableEurekaClient @EnableFeignClients public class HytrixConsumer81 { public static void main(String[] args) { SpringApplication.run(HytrixConsumer81.class,args); } }
Feigin接口
package com.liuxu.feign; import com.liuxu.result.CommResult; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; /** * @author liuxu * @date 2021/10/29 21:06 */ @FeignClient("cloud-hystrix-provider") public interface Providers { @RequestMapping("/hystrix/ok") public String ok(); @RequestMapping("/hystrix/err") public String timeOut(); }
controller
package com.liuxu.controller; import com.liuxu.feign.Providers; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author liuxu * @date 2021/10/30 21:54 */ @RestController @RequestMapping("/hytrix/comsumer") public class HystrixController { @Autowired Providers providers; @RequestMapping("/ok") public String ok(){ return providers.ok(); }; @RequestMapping("/err") public String timeOut(){ return providers.timeOut(); }; }
启动 7001 注册中心 8001 服务提供方 81 feign调用方
访问http://localhost:81/hytrix/comsumer/ok 可以正常返回
访问http://localhost:81/hytrix/comsumer/err会超时 出现问题的原因之前在OpenFeign章节提到过
Feign 调用服务时默认等待时间是1s,而err接口程序需要运行3s>1s
这个时候就需要hytrix来解决问题了
解决:
1.服务提供方8001超时,调用者81不能一直卡死等待,需要有降级返回
2.服务提供方8001宕机,调用者81不能一直卡死等待,需要有降级返回
3.调用者自身出现故障,需要有降级返回
首先在8001自身解决问题 自身加固,异常和超时添加默认返回
controller层添加fallBack 回调
package com.liuxu.controller; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.TimeUnit; /** * @author liuxu * @date 2021/10/30 20:17 */ @RestController @RequestMapping("hystrix/") public class PayController { @Value("${server.port}") String port; @RequestMapping("/ok") public String paymentinfo_ok(){ return "端口"+port+ "hystrix 提供者正常返回,线程池是:"+Thread.currentThread().getName(); } @RequestMapping("/err") @HystrixCommand(fallbackMethod = "proTimeOutFallback",commandProperties = { @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS,value = "1000") }) public String paymentinfo_err(){ try{ TimeUnit.SECONDS.sleep(3); }catch (Exception e){ e.printStackTrace(); } return "端口"+port+"hystrix 提供者超时返回,线程池是:"+Thread.currentThread().getName(); } @RequestMapping("/get0") @HystrixCommand(fallbackMethod = "get0Fallback",commandProperties = { @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS,value = "1000") }) public String get0(){ int i=10/0; return "端口"+port+"hystrix 提供者超时返回,线程池是:"+Thread.currentThread().getName(); } public String proTimeOutFallback(){ return "8001系统繁忙,请稍后重试<>线程是:"+Thread.currentThread().getName(); } public String get0Fallback(){ return "8001系统异常,线程是:"+Thread.currentThread().getName(); } }
主启动类开始熔断
package com.liuxu; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; /** * @author liuxu * @date 2021/10/30 20:15 */ @SpringBootApplication @EnableEurekaClient @EnableCircuitBreaker //开启服务熔断 public class HystrixProvider8001 { public static void main(String[] args) { SpringApplication.run(HystrixProvider8001.class,args); } }
重启8001
首次访问http://localhost:8001/hystrix/err 发现1s(实际代码中构造了3s等待)后就会返回,返回值为fallback方法返回值
短时间内再次访问直接返回 fallback方法返回值
http://localhost:8001/hystrix/get0 不会出现异常
返回对应fallback返回值
8001 自身加固完成
消费方81将Feign等待时间设置大于1s(提供方熔断器设置的超时时间)小于3s(提供方程序超时时间)
实际上配置的是ribbon的超时时间
ribbon: ###指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间。 ReadTimeout: 2000 ###指的是建立连接后从服务器读取到可用资源所用的时间。 ConnectTimeout: 5000
此时在访问 http://localhost:81/hytrix/comsumer/err
通过服务方调用超时接口 ,发现断路器生效,返回了超时接口的 降级方法
81 服务消费方配置服务熔断降级
首先Feign自带Hystrix降级,需要开启降级策略
配置文件开启降级
feign: hystrix: enabled: true #开启服务降级
主启动类开启断路器 @EnableHystrix
package com.liuxu; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.hystrix.EnableHystrix; import org.springframework.cloud.openfeign.EnableFeignClients; /** * @author liuxu * @date 2021/10/27 21:45 */ @SpringBootApplication @EnableEurekaClient @EnableFeignClients @EnableHystrix //开启服务降级 public class HytrixConsumer81 { public static void main(String[] args) { SpringApplication.run(HytrixConsumer81.class,args); } }
Providers 添加了调用 8001 get0接口的方法代码,属于OpenFeign内容,如果不明白,请回头看OpenFeign章节,这里Providers 代码不再展示
controller层添加降级测策略
package com.liuxu.controller; import com.liuxu.feign.Providers; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author liuxu * @date 2021/10/30 21:54 */ @RestController @RequestMapping("/hytrix/comsumer") public class HystrixController { @Autowired Providers providers; @RequestMapping("/ok") public String ok(){ return providers.ok(); }; @RequestMapping("/err") @HystrixCommand(fallbackMethod = "proTimeOutFallback",commandProperties = { @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS,value = "1000") }) public String timeOut(){ return providers.timeOut(); }; @RequestMapping("/get0") @HystrixCommand(fallbackMethod = "get0Fallback",commandProperties = { @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS,value = "1000") }) public String get0(){ return providers.get0(); }; public String proTimeOutFallback(){ return "服务消费方降级,8001系统繁忙,请稍后重试<>线程是:"+Thread.currentThread().getName(); } public String get0Fallback(){ return "服务消费方降级,8001系统异常,线程是:"+Thread.currentThread().getName(); } }
将服务提供方超时降级策略调整,保证81 消费到3s的服务调用接口
8001controller修改err接口降级策略
@RequestMapping("/err")
@HystrixCommand(fallbackMethod = "proTimeOutFallback",commandProperties = {
@HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS,value = "5000")
})
package com.liuxu.controller; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.TimeUnit; /** * @author liuxu * @date 2021/10/30 20:17 */ @RestController @RequestMapping("hystrix/") public class PayController { @Value("${server.port}") String port; @RequestMapping("/ok") public String paymentinfo_ok(){ return "端口"+port+ "hystrix 提供者正常返回,线程池是:"+Thread.currentThread().getName(); } @RequestMapping("/err") @HystrixCommand(fallbackMethod = "proTimeOutFallback",commandProperties = { @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS,value = "5000") }) public String paymentinfo_err(){ try{ TimeUnit.SECONDS.sleep(3); }catch (Exception e){ e.printStackTrace(); } return "端口"+port+"hystrix 提供者超时返回,线程池是:"+Thread.currentThread().getName(); } @RequestMapping("/get0") @HystrixCommand(fallbackMethod = "get0Fallback",commandProperties = { @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS,value = "1000") }) public String get0(){ int i=10/0; return "端口"+port+"hystrix 提供者超时返回,线程池是:"+Thread.currentThread().getName(); } public String proTimeOutFallback(){ return "8001系统繁忙,请稍后重试<>线程是:"+Thread.currentThread().getName(); } public String get0Fallback(){ return "8001系统异常,线程是:"+Thread.currentThread().getName(); } }
此时访问http://localhost:81/hytrix/comsumer/err
发现执行的是消费方的降级策略
访问http://localhost:81/hytrix/comsumer/get0
发现执行的是服务提供方的降级策略
总结 服务降级可以用到服务提供方和服务消费方
服务提供方降级策略受 自身代码的运行时长 异常情况
消费端的降级策略受服务端的响应时间 异常情况影响 当然也包括自身代码的运行时长 异常情况
没必要所有方法都配置服务降级方法 可以设置全局的服务降级方法
消费方81controller类上配置
@DefaultProperties(defaultFallback="global_FallbackMethod")
再指定全局异 降级方法global_FallbackMethod
package com.liuxu.controller; import com.liuxu.feign.Providers; 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.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author liuxu * @date 2021/10/30 21:54 */ @RestController @RequestMapping("/hytrix/comsumer") @DefaultProperties(defaultFallback="global_FallbackMethod") public class HystrixController { @Autowired Providers providers; @RequestMapping("/ok") public String ok(){ return providers.ok(); }; @RequestMapping("/err") @HystrixCommand /* @HystrixCommand(fallbackMethod = "proTimeOutFallback",commandProperties = { @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS,value = "1000") })*/ public String timeOut(){ return providers.timeOut(); }; @RequestMapping("/get0") @HystrixCommand(fallbackMethod = "get0Fallback",commandProperties = { @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS,value = "1000") }) public String get0(){ return providers.get0(); }; public String proTimeOutFallback(){ return "服务消费方降级,8001系统繁忙,请稍后重试<>线程是:"+Thread.currentThread().getName(); } public String get0Fallback(){ return "服务消费方降级,8001系统异常,线程是:"+Thread.currentThread().getName(); } public String global_FallbackMethod(){ return "全局默认Fallback方法"; } }
访问http://localhost:81/hytrix/comsumer/get0
此接口配置了自己的降级方法 走自己的降级方法
访问http://localhost:81/hytrix/comsumer/err
此接口未配置降级方法只配置了@HystrixCommand 会走全局默认降级方法
全局降级配置可以在HystrixPropertiesManager找到 ,可以在配置文件中配置各个参数然后查看默认降级效果
下面介绍了默认降级各个参数的含义
/** * Command execution properties. */ public static final String EXECUTION_ISOLATION_STRATEGY = "execution.isolation.strategy"; public static final String EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS = "execution.isolation.thread.timeoutInMilliseconds"; public static final String EXECUTION_TIMEOUT_ENABLED = "execution.timeout.enabled"; public static final String EXECUTION_ISOLATION_THREAD_INTERRUPT_ON_TIMEOUT = "execution.isolation.thread.interruptOnTimeout"; public static final String EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS = "execution.isolation.semaphore.maxConcurrentRequests"; /** * Command fallback properties. */ public static final String FALLBACK_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS = "fallback.isolation.semaphore.maxConcurrentRequests"; public static final String FALLBACK_ENABLED = "fallback.enabled"; /** * Command circuit breaker properties. */ public static final String CIRCUIT_BREAKER_ENABLED = "circuitBreaker.enabled"; public static final String CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD = "circuitBreaker.requestVolumeThreshold"; public static final String CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS = "circuitBreaker.sleepWindowInMilliseconds"; public static final String CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE = "circuitBreaker.errorThresholdPercentage"; public static final String CIRCUIT_BREAKER_FORCE_OPEN = "circuitBreaker.forceOpen"; public static final String CIRCUIT_BREAKER_FORCE_CLOSED = "circuitBreaker.forceClosed"; /** * Command metrics properties. */ public static final String METRICS_ROLLING_PERCENTILE_ENABLED = "metrics.rollingPercentile.enabled"; public static final String METRICS_ROLLING_PERCENTILE_TIME_IN_MILLISECONDS = "metrics.rollingPercentile.timeInMilliseconds"; public static final String METRICS_ROLLING_PERCENTILE_NUM_BUCKETS = "metrics.rollingPercentile.numBuckets"; public static final String METRICS_ROLLING_PERCENTILE_BUCKET_SIZE = "metrics.rollingPercentile.bucketSize"; public static final String METRICS_HEALTH_SNAPSHOT_INTERVAL_IN_MILLISECONDS = "metrics.healthSnapshot.intervalInMilliseconds"; /** * Command CommandRequest Context properties. */ public static final String REQUEST_CACHE_ENABLED = "requestCache.enabled"; public static final String REQUEST_LOG_ENABLED = "requestLog.enabled"; /** * Thread pool properties. */ public static final String MAX_QUEUE_SIZE = "maxQueueSize"; public static final String CORE_SIZE = "coreSize"; public static final String KEEP_ALIVE_TIME_MINUTES = "keepAliveTimeMinutes"; public static final String QUEUE_SIZE_REJECTION_THRESHOLD = "queueSizeRejectionThreshold"; public static final String METRICS_ROLLING_STATS_NUM_BUCKETS = "metrics.rollingStats.numBuckets"; public static final String METRICS_ROLLING_STATS_TIME_IN_MILLISECONDS = "metrics.rollingStats.timeInMilliseconds"; /** * Collapser properties. */ public static final String MAX_REQUESTS_IN_BATCH = "maxRequestsInBatch"; public static final String TIMER_DELAY_IN_MILLISECONDS = "timerDelayInMilliseconds";
默认赋值都在HystrixCommandProperties中
下面在81controller添加熔断测试的接口
@RequestMapping("circuit/{id}") public String circuitBreaker(@PathVariable Integer id){ if(id>0){ return "正常返回id是:"+id; }else { throw new RuntimeException("id不能为负数"); } };
重启81访问
http://localhost:81/hytrix/comsumer/circuit/1 正常返回
http://localhost:81/hytrix/comsumer/circuit/-1 跑出异常
下面添加熔断设置处理该问题yml中添熔断相关配置
cloud:
# 服务熔断相关配置
circuitbreaker:
requestVolumeThreshold: 10 # 请求次数
sleepWindowInMilliseconds: 10000 # 时间窗口期
errorThresholdPercentage: 60 # 失败率达到多少后开启 60%
hystrix:
enabled: true # 是否开启断路器
server: port: 81 #端口号 spring: application: name: cloud-hytrix-consumer-81 #服务名 cloud: # 服务熔断相关配置 circuitbreaker: requestVolumeThreshold: 10 # 请求次数 sleepWindowInMilliseconds: 10000 # 时间窗口期 errorThresholdPercentage: 60 # 失败率达到多少后开启 60% hystrix: enabled: true # 是否开启断路器 eureka: client: # 是否从Eureka抓取注册信息 单节点情况下无用 集群情况下才能配合robbion使用负载均衡 fetch-registry: true # 注册如Eureka 用 true register-with-eureka: true service-url: # 设置与eureka server交互的地址查询和注册服务都需要这个地址 向注册中心注册 defaultZone: http://localhost:7001/eureka/ ribbon: ###指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间。 ReadTimeout: 2000 ###指的是建立连接后从服务器读取到可用资源所用的时间。 ConnectTimeout: 5000 feign: hystrix: enabled: true #开启服务降级
接口处添加@HystrixCommand注解 并指定fallback方法
@RequestMapping("circuit/{id}") @HystrixCommand(fallbackMethod = "circuitBreakerFallback") public String circuitBreaker(@PathVariable Integer id){ if(id>0){ return "正常返回id是:"+id; }else { throw new RuntimeException("id不能为负数"); } }; public String circuitBreakerFallback(Integer id){ return "参数id不能为负数"+id; }
重启81
访问 http://localhost:81/hytrix/comsumer/circuit/-1 发现已经走fallback方法
http://localhost:81/hytrix/comsumer/circuit/1 正常返回
以上看上去和降级没有区别
实际上服务熔断后也会走降级方法
这时候如果用jmeter访问 使的请求次数在10s(时间窗口期)内超出10个,而且错误率超过60%
这个时候再访问 http://localhost:81/hytrix/comsumer/circuit/1
发现依然降级
停止jmeter的错误
一段时间后
http://localhost:81/hytrix/comsumer/circuit/1回复正常
熔断和降级的区别是 熔断能够自我恢复
配置文件中提到了断路器的三个重要参数:快照时间窗口、请求总数阈值、错误百分比
时间快照: 断路器打开是根据一段时间的请求和错误数据的统计来决定的,时间快照就是统计的单位时间 默认最近10s
请求总数阈值 :10s内的请求总数阈值,默认20个,就是说即使10s内的请求一直失败,但是没有达到20 也不会打开断路器
错误百分比: 默认50% 10s内请求错误的百分比
综合上述三个参数 默认情况下请求在10s内次数达到20,错误比率达到50%断路器会打开