赞
踩
上期SpringCloud(二):服务调用和负载均衡通过Eureka注册中心构建一个简单微服务,并通过RestTemplate
进行远程调用。当系统中微服务较多,某些微服务会不可避免出现异常。
在微服务架构中,服务与服务之间存在相互调用关系。一旦某个微服务发生故障,则依赖该微服务的所有服务都会发生故障,最终导致整个系统瘫痪。
Hystrix实现了断路器,当服务发生故障后会返回给调用者一个响应,而不是长时间等待导致进程一直被占用,减少了故障的蔓延。熔断器工作逻辑如下
Closed
:熔断器开始处于关闭状态,服务正常处理。
Open
:检测到一定比例异常时熔断器打开。
Half Open
:经过reset timeout时间进入半开状态,此时会尝试放行一部分请求,如果成功处理进入关闭状态。
Hystrix已经不在处于开发状态,但是仍处于维护状态。
修改之前创建的cloud-provider-payment模块,使其支持服务降级与熔断。修改pom文件,引入hystirx依赖。
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
在主启动类上加入@EnableHystrix
注解。
@SpringBootApplication
@EnableEurekaClient
@EnableHystrix
public class PaymentMainApplication {
public static void main(String[] args) {
SpringApplication.run(PaymentMainApplication.class, args);
}
}
在PaymentController
中加入用于测试服务降级的方法。
/**
* 演示服务降级
* @param id 传入id
* @return String
*/
@GetMapping("/provider/testFallback/{id}")
public String testFallback(@PathVariable("id") Integer id){
return paymentService.testFallback(id);
}
新建一个PaymentService
接口,定义测试方式,并新建该接口实现类,实现测试方法。
public interface PaymentService {
String testFallback(Integer id);
}
接口实现如下
@Service
public class PaymentServiceImpl implements PaymentService {
@Override
public String testFallback(Integer id) {
int a = 10 / id;
return "输入id为:" + id + " 计算结果为:" + a;
}
}
当业务逻辑出现异常时服务降级会返回一个可以接受的错误结果,阻止异常蔓延。因此要实现服务降级需要定义一个备选方法,用以返回一个可以接受的错误结果。
在PaymentService
中加入@HystrixCommand
注解,定义降级调用方法如下。
@Service
public class PaymentServiceImpl implements PaymentService {
@Override
@HystrixCommand(fallbackMethod = "getDefaultResult")
public String testFallback(Integer id) {
int a = 10 / id;
return "输入id为:" + id + " 计算结果为:" + a;
}
private String getDefaultResult(Integer id) {
return "输入id为:" + id + "非法!无法计算结果!";
}
}
启动 Eureka Server和 cloud-provider-payment。
首先访问其中一个注册中心http://localhost:7001/,可以看到注册中心集群启动,并且payment服务已经注册。
根据定义的逻辑,如果传入id不为0就不会发生异常。首先访问正常地址http://localhost:8001/provider/testFallback/1
如果传入id为0会抛出算术异常,这时就会调用服务降级方法。访问错误地址http://localhost:8001/provider/testFallback/0
这里显示的是事先定义的服务降级的返回值。
该注解常用参数
对于上述案例,如果想要放行算术异常,可以使用ignoreExceptions
配置。
@Override
@HystrixCommand(fallbackMethod = "getDefaultResult",
ignoreExceptions = ArithmeticException.class)
public String testFallback(Integer id) {
int a = 10 / id;
return "输入id为:" + id + " 计算结果为:" + a;
}
重启服务后访问http://localhost:8001/provider/testFallback/0
此时未采用服务降级,而是直接报出内部服务错误异常。
上述例子只能笼统处理一些运行时服务的服务降级,如果想要更细粒度进行服务降级就要配置@HystrixCommand
注解的commandProperties
属性。要配置该属性需要用到@HystrixProperty
注解。
例如如果一个服务运行时间过长,则就算在正常进行我们也对其进行降级。controller层测试接口如下。
/**
* 演示超时服务降级
* @return String
*/
@GetMapping("/provider/testTimeout")
public String testTimeout(){
return paymentService.testTimeout();
}
对应service层处理如下,假设一个服务因为业务繁忙需要处理一秒,但是我们只能等待0.5s,则对该服务进行降级处理,防止该服务长时间占用线程。
@Override @HystrixCommand(fallbackMethod = "handleTimeout",commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "500") }) public String testTimeout() { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { throw new RuntimeException(e); } return "程序处理完毕!"; } public String handleTimeout(){ return "程序长时间无响应,请稍后再试!"; }
访问测试地址http://localhost:8001/provider/testTimeout,看到如下界面
Command属性主要用来控制HystrixCommand命令的行为,它主要分下面的类别:
1、Execution:用来控制HystrixCommand.run()的执行
execution.isolation.strategy
:该属性用来设置HystrixCommand.run()执行的隔离策略。默认为THREAD。execution.isolation.thread.timeoutInMilliseconds
:该属性用来配置HystrixCommand执行的超时时间,单位为毫秒。execution.timeout.enabled
:该属性用来配置HystrixCommand.run()的执行是否启用超时时间。默认为true。execution.isolation.thread.interruptOnTimeout
:该属性用来配置当HystrixCommand.run()执行超时的时候是否要它中断。execution.isolation.thread.interruptOnCancel
:该属性用来配置当HystrixCommand.run()执行取消时是否要它中断。execution.isolation.semaphore.maxConcurrentRequests
:当HystrixCommand命令的隔离策略使用信号量时,该属性用来配置信号量的大小。当最大并发请求达到该设置值时,后续的请求将被拒绝。2、Fallback:用来控制HystrixCommand.getFallback()的执行
fallback.isolation.semaphore.maxConcurrentRequests
:该属性用来设置从调用线程中允许HystrixCommand.getFallback()方法执行的最大并发请求数。当达到最大并发请求时,后续的请求将会被拒绝并抛出异常。fallback.enabled
:该属性用来设置服务降级策略是否启用,默认是true。如果设置为false,当请求失败或者拒绝发生时,将不会调用HystrixCommand.getFallback()来执行服务降级逻辑。3、Circuit Breaker:用来控制HystrixCircuitBreaker的行为。
circuitBreaker.enabled
:确定当服务请求命令失败时,是否使用断路器来跟踪其健康指标和熔断请求。默认为true。circuitBreaker.requestVolumeThreshold
:用来设置在滚动时间窗中,断路器熔断的最小请求数。例如,默认该值为20的时候,如果滚动时间窗(默认10秒)内仅收到19个请求,即使这19个请求都失败了,断路器也不会打开。circuitBreaker.sleepWindowInMilliseconds
:用来设置当断路器打开之后的休眠时间窗。休眠时间窗结束之后,会将断路器设置为“半开”状态,尝试熔断的请求命令,如果依然失败就将断路器继续设置为“打开”状态,如果成功,就设置为“关闭”状态。circuitBreaker.errorThresholdPercentage
:该属性用来设置断路器打开的错误百分比条件。默认值为50,表示在滚动时间窗中,在请求值超过requestVolumeThreshold阈值的前提下,如果错误请求数百分比超过50,就把断路器设置为“打开”状态,否则就设置为“关闭”状态。circuitBreaker.forceOpen
:该属性默认为false。如果该属性设置为true,断路器将强制进入“打开”状态,它会拒绝所有请求。该属性优于forceClosed属性。circuitBreaker.forceClosed
:该属性默认为false。如果该属性设置为true,断路器强制进入“关闭”状态,它会接收所有请求。如果forceOpen属性为true,该属性不生效。4、Metrics:该属性与HystrixCommand和HystrixObservableCommand执行中捕获的指标相关。
metrics.rollingStats.timeInMilliseconds
:该属性用来设置滚动时间窗的长度,单位为毫秒。该时间用于断路器判断健康度时需要收集信息的持续时间。断路器在收集指标信息时会根据设置的时间窗长度拆分成多个桶来累计各度量值,每个桶记录了一段时间的采集指标。例如,当为默认值10000毫秒时,断路器默认将其分成10个桶,每个桶记录1000毫秒内的指标信息。metrics.rollingStats.numBuckets
:用来设置滚动时间窗统计指标信息时划分“桶”的数量。默认值为10。metrics.rollingPercentile.enabled
:用来设置对命令执行延迟是否使用百分位数来跟踪和计算。默认为true,如果设置为false,那么所有的概要统计都将返回-1。metrics.rollingPercentile.timeInMilliseconds
:用来设置百分位统计的滚动窗口的持续时间,单位为毫秒。metrics.rollingPercentile.numBuckets
:用来设置百分位统计滚动窗口中使用桶的数量。metrics.rollingPercentile.bucketSize
:用来设置每个“桶”中保留的最大执行数。metrics.healthSnapshot.intervalInMilliseconds
:用来设置采集影响断路器状态的健康快照的间隔等待时间。5、Request Context:涉及HystrixCommand使用HystrixRequestContext的设置。
requestCache.enabled
:用来配置是否开启请求缓存。requestLog.enabled
:用来设置HystrixCommand的执行和事件是否打印到日志的HystrixRequestLog中。假设某个服务要求5秒内请求次数超过5次且异常概率超过60%就打开熔断器,熔断器休眠窗口为5s。建立测试接口如下
@GetMapping("/provider/testProperties/{id}")
public String testProperties(@PathVariable("id") Integer id){
return paymentService.testProperties(id);
}
service层编码如下
@Override @HystrixCommand(fallbackMethod = "defaultHandle", commandProperties = { @HystrixProperty(name = "circuitBreaker.enabled", value = "true"), // 开始熔断器,默认开启可不写 @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "5000"), // 时间窗口 @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "5"), // 最少请求次数 @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"), // 异常百分比 @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000") // 熔断器休眠窗口 }) public String testProperties(Integer id) { int a = 10 / id; return "输入id为:" + id + " 计算结果为:" + a; } private String defaultHandle(Integer id) { return "输入id为:" + id + "非法!无法计算结果!"; }
我们在五秒内发送至少5次请求,其中3次携带id为0造成异常,这时断路器会打开,在之后的5秒无论请求正确与否都会直接进入服务降级。
首先访问正常地址,得到正常结果。
然后修改id为0,在5s内多次发送错误,打开熔断器。
熔断器开启,将id设为正常值会发现仍然进行服务降级。
等待熔断器窗口期过后进入半开状态,如果处理请求仍然异常,则再次进去打开状态,继续等下一个窗口期,如果成功处理则将熔断器关闭。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。