从0开始用SpringCloud搭建微服务系统【四】

容错

基本的容错模式有:

  • 主动超时:
  • 限流:限制最大并发数
  • 熔断:错误数达到阈值时,类似保险丝熔断
  • 隔离:隔离不同的依赖调用或者隔离不同的线程
  • 降级:服务降低

容错理念:

  • 凡是依赖都可能会失败
  • 凡是资源都有限制
    • CPU/Memory/Threads/Queue
  • 网络并不可靠
  • 延迟是应用稳定性杀手

Netflix Hystrix

Hystrix实现了 超时机制和断路器模式。

Hystrix是Netflix开源的一个类库,用于隔离远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。主要有以下几点功能:

  • 为系统提供保护机制。在依赖的服务出现高延迟或失败时,为系统提供保护和控制。
  • 防止雪崩。
  • 包裹请求:使用HystrixCommand(或HystrixObservableCommand)包裹对依赖的调用逻辑,每个命令在独立线程中运行。
  • 跳闸机制:当某服务失败率达到一定的阈值时,Hystrix可以自动跳闸,停止请求该服务一段时间。
  • 资源隔离:Hystrix为每个请求都的依赖都维护了一个小型线程池,如果该线程池已满,发往该依赖的请求就被立即拒绝,而不是排队等候,从而加速失败判定。防止级联失败。
  • 快速失败:Fail Fast。同时能快速恢复。侧重点是:(不去真正的请求服务,发生异常再返回),而是直接失败。
  • 监控:Hystrix可以实时监控运行指标和配置的变化,提供近实时的监控、报警、运维控制。
  • 回退机制:fallback,当请求失败、超时、被拒绝,或当断路器被打开时,执行回退逻辑。回退逻辑我们自定义,提供优雅的服务降级。
  • 自我修复:断路器打开一段时间后,会自动进入“半开”状态,可以进行打开,关闭,半开状态的转换。

Hystrix设计原理

Hystrix的工作原理可以可以参考官网的How it Works。如果要看中文版,可以参考:Hystrix工作原理

信号量隔离与线程隔离

默认情况下hystrix使用线程池控制请求隔离

线程池隔离技术,是用 Hystrix 自己的线程去执行调用;而信号量隔离技术,是直接让 tomcat 线程去调用依赖服务。信号量隔离,只是一道关卡,信号量有多少,就允许多少个 tomcat 线程通过它,然后去执行。

信号量隔离主要维护的是Tomcat的线程,不需要内部线程池,更加轻量级。

优点 不足 适用
信号量隔离 轻量,无额外开销 不支持任务排队和主动超时
不支持异步调用
受信客户
高扇出(网关)
高频高速调用(cache)
线程池隔离 支持排队和超时
支持异步调用
线程调用会产生额外的开销 不受信客户
有限扇出

使用Hystrix

独立使用

独立使用Hystrix可以参考How To Use

如果想要中文,可以参考:Hystrix都停更了,我为什么还要学?

与Resttemplate整合

引入依赖spring-cloud-starter-netflix-hystrix

在Service中:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Service
public class GreetingService {
@HystrixCommand(fallbackMethod = "defaultGreeting")
public String getGreeting(String username) {
return new RestTemplate()
.getForObject("http://localhost:9090/greeting/{username}",
String.class, username);
}
private String defaultGreeting(String username) {
return "Hello User!";
}
}

在Application中:

1
2
3
4
5
6
7
@SpringBootApplication
@EnableCircuitBreaker
public class RestConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(RestConsumerApplication.class, args);
}
}

@EnableCircuitBreaker注释将扫描类路径以查找任何兼容的Circuit Breaker实现。

与Feign整合

在集成Feign的基础上修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@FeignClient(name = "statistics-service", fallback = StatisticsServiceClientFallback.class)
public interface StatisticsServiceClient {
@RequestMapping(method = RequestMethod.PUT, value = "/statistics/{accountName}")
void updateStatistics(@PathVariable("accountName") String accountName, Account account);
}
@Component
@Slf4j
public class StatisticsServiceClientFallback implements StatisticsServiceClient {
@Override
public void updateStatistics(String accountName, Account account) {
log.error("Error during update statistics for account: {}", accountName);
}
}

然后在配置文件中打开:

1
feign.hystrix.enabled=true

使用fallbackFactory检查具体错误

在一些场景中,简单的触发在 FeignClient 加入 Fallback 属性即可,而另外有一些场景需要访问导致回退触发的原因,那么这个时候可以在 FeignClient 中加入 FallbackFactory 属性即可;

  1. 定义一个类,实现FallbackFactory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Component
public class WebError implements FallbackFactory<ConsumerApi> {
@Override
public ConsumerApi create(Throwable cause) {
return new ConsumerApi() {
@Override
public String getById(Integer id) {
//针对不同异常返回响应
if(cause instanceof InternalServerError) {
System.out.println("InternalServerError");
return "远程服务报错";
}else if(cause instanceof RuntimeException) {
return "请求时异常:" + cause;
}else {
return "都算不上";
}
return null;
}
};
}
}
  1. @Feign中的使用@FeignClient(name = "statistics-service", fallbackFactory = WebError.class)

主要配置项

配置项(前缀hystrix.command.*.) 含义
execution.isolation.strategy 线程“THREAD”或信号量“SEMAPHORE”隔离(Default: THREAD)
execution.isolation.thread.timeoutInMilliseconds run()方法执行超时时间(Default: 1000)
execution.isolation.semaphore.maxConcurrentRequests 信号量隔离最大并发数(Default:10)
circuitBreaker.errorThresholdPercentage 熔断的错误百分比阀值(Default:50)
circuitBreaker.requestVolumeThreshold 断路器生效必须满足的流量阀值(Default:20)
circuitBreaker.sleepWindowInMilliseconds 熔断后重置断路器的时间间隔(Default:5000)
circuitBreaker.forceOpen 设true表示强制熔断器进入打开状态(Default: false)
circuitBreaker.forceClosed 设true表示强制熔断器进入关闭状态(Default: false)
配置项(前缀hystrix.threadpool.*.) 含义
coreSize 使用线程池时的最大并发请求(Default: 10)
maxQueueSize 最大LinkedBlockingQueue大小,-1表示用SynchronousQueue(Default:-1)
default.queueSizeRejectionThreshold 队列大小阀值,超过则拒绝(Default:5)

Hystrix Dashboard

Hystrix有一个不错的可选功能是能够在仪表板上监视其状态。 为了启用它,我们将spring-cloud-starter-hystrix-dashboardspring-boot-starter-actuator放入项目的pom.xml中。

然后添加@EnableHystrixDashboard注解。

启动应用程序后,将浏览器指向http://localhost:8080/hystrix,输入“ hystrix.stream”的指标URL并开始监视。

参考: