Hystrix组件
1、服务器容错核心知识
1.1、雪崩效应
在微服务架构中,一个请求需要调用多个服务是非常常见的。如客户端访问A服务,而A服务需要调用B 服务,B服务需要调用C服务,由于网络原因或者自身的原因,如果B服务或者C服务不能及时响应,A服 务每处于阻塞状态,直到B服务C服务响应。此时若有大量的请求涌入,容器的线程资源会被消耗完毕, 导致服务簿痪。服务与服务之间的依赖性,故障会传播,造成连锁反应,会对整个微服务系统造成灾难 性的严重后果,这就是服务故障的"雪崩"效应。
1.2、服务隔离
将系统按照一定的原则划分为若干个服务模块,各个模块之间相对独立,无强依赖。当有故障发生时,能将问题和影响隔离在某个模块内部,而不扩散风险,不波及其他模块,不影响整体的系统服务。
1.3、熔断降级
熔断这一概念来源于电子工程中的熔断器(Circuit Breaker)。在互联网系统中,当下游服务因访问压力而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。这种牺牲局部,保全整体的措施就叫做熔断。
所谓降级,就是当某个服务熔断之后,服务器将不再被调用,此时客户端可以自己准备一个本地的
1.4、服务限流
限流可以认为服务降级的一种,限流就是限制系统的输入和输出流量以到达保护系统的目的。一般来说系统的吞吐量是可以被测算的,为了保证系统的稳固运行,一旦达到的需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的目的。比如:推迟解决,拒绝解决,或者部分拒绝等等。
2、Hystrix
Hystrix是由Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。Hystrix主要通过以下几点实现延迟和容错。
- 包裹谪求:使用HystrixCommand包裹对依赖的调用逻辑,每个命令在独立线程中执行。这使用了设计横式中的"命令横式
- 跳间机制:当某服务的错误率超过一定的阈值时,Hystrix可以自动或手动跳闸,停止谪求该服务一段时间。
- 资源隔离:Hystrix为每个依赖都维护了一个小型的线程池(或者信号量)。如果该线程池已满,发往该依赖的谪求就被立即拒绝,而不是排队等待,从而加速失败判定。
- 监 控 : Hystrix可以近乎实时地监控运行指标和配置的变化,例如成功、失败、超时、以及被拒绝的谪求等。
- 回退机制:当请求失败、超时、被拒绝,或当断路器打开时,执行回退逻辑。回退逻辑由开发人员自行提供,例如返回一个缺省值。
- 自我修复:断路器打开一段时间后,会自动进入“半开”状态。
3、Rest实现服务熔断
3.1 基本配置
3.1.1、引入hystrix依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
3.1.2、在启动类中激活hystrix
//激活Hystrix
@EnableCircuitBreaker
@SpringBootApplication
public class ConsumerFeignApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerFeignApplication.class,args);
}
}
3.1.2、配置熔断出发的降级逻辑
/**
* 降级方法
* 和需要受到保护的方法的参数及返回值类型一致
*/
public User userFallBack(Long id){
return new User();
}
3.1.4、在需要受到保护的接口上使用@HystrixCommand配置
/**
* 使用注解配置熔断保护
* fallbackMethod:配置熔断之后的降级方法
*/
@HystrixCommand(fallbackMethod = "userFallBack")
@GetMapping("/getUserBalanceById/{id}")
public User getUserBalanceById(@PathVariable Long id){
//根据服务注册名称获取服务实例列表
String url = "http://user-service/user/getUserById/"+id;
return restTemplate.getForObject(url,User.class);
}
超时设置
Hystrix默认超时时长为1s,超过1s后会自动触发熔断降级方法。可以修改配置参数:
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 2000 #默认的连接超时时间是1s
3.2 RestTemplate统一的降级配置
3.2.1 配置统一降级方法
/**
* 指定统一的降级方法
* 没有参数
*/
public User defaultFallBack(){
return new User();
}
3.2.2 配置统一降级方法
@RestController
@RequestMapping("/consumer")
/**
* @DefaultProperties:指定此接口中公共的熔断设置
* 如果在@DefaultProperties指定了公共的降级方法
* 在@HystrixCommand中可以不用单独指定
*/
@DefaultProperties(defaultFallback = "defaultFallBack")
public class ConsumerController {...}
4、Feign实现服务熔断
引入依赖(feign中已经集成了Hystrix)
在feign中配置了开启Hystrix
feign:
#配置日志级别
client:
config:
USER-SERVICE:
loggerLevel: FULL
#开启对hystrix的支持
hystrix:
enabled: true
自定义一个接口的实现类,这个实现类就是熔断出发的降级逻辑
@Component
public class UserFeignClientCallBack implements UserFeignClient{
/**
* 熔断降级的方法
*/
public User getUserById(Long id) {
return new User();
}
}
修改FeignClient接口,添加降级方法的支持
/**
* 声明需要调用的微服务名称
* @FeignClient
* *name:服务提供者的名称
* *fallback:配置熔断降级的方法配置类
*/
@FeignClient(name = "USER-SERVICE",fallback = UserFeignClientCallBack.class)
public interface UserFeignClient {
@RequestMapping(value = "/user/getUserById/{id}",method = RequestMethod.GET)
User getUserById(@PathVariable("id") Long id);
}
5、Hystrix设置监控信息
基本监控
引入坐标
<!--引入Hystrix的监控信息-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
在启动类上配置
//开启Feign注解
@EnableFeignClients
//激活Hystrix
@EnableCircuitBreaker
@SpringBootApplication
public class ConsumerFeignApplication {...}
暴露所有actuator监控的断点
management:
endpoints:
web:
exposure:
include: '*'
在页面上访问http://ip:port/actuator/hystrix.stream
web监控页面
引入坐标
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
激活hystrix的web监控平台
//开启Feign注解
@EnableFeignClients
//激活Hystrix
@EnableCircuitBreaker
//激活hystrix的web监控平台
@EnableHystrixDashboard
@SpringBootApplication
public class ConsumerFeignApplication {...}
打开监控页面
http://ip:port/hystrix
输入上一步的stream路径
Turbine 熔断器聚合统一监控
新建项目引入坐标
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
添加配置项
server:
port: 8031
spring:
application:
name: hystrix-trubine
eureka:
client:
service-url:
defaultZone: http://localhost:9001/eureka/
instance:
prefer-ip-address: true
turbine:
# 要监控的微服务列表,多个用','隔开
app-config: consumer-service
cluster-name-expression: "'default'"
配置启动项
//激活turbine配置
@EnableTurbine
@EnableHystrixDashboard
@SpringBootApplication
public class TurbineApplication {
public static void main(String[] args) {
SpringApplication.run(TurbineApplication.class,args);
}
}
在监控页面输入turbine监控流查看聚合监控
hystrix可以对请求失败的请求,以及被拒绝或者超时的请求进行统一的降级处理。
6、断路器
断路器状态
Closed(关闭),Open(开启),Half Open(半开)
Closed(关闭)
所有的请求都可以正常访问
可配置请求次数大于20次,且存在50%的失败概率
Open(开启)
所有请求会进入到降级方法中
Half Open(半开)
维持Open状态一段时间(默认5s),然后进入到半开状态(尝试释放一个请求到远程微服务发起调用)
如果释放的请求可以正常访问,就会关闭断路器
如果释放的请求不能正常访问,继 续保持开启状态5s
断路器的隔离策略
微服务使用Hystrix熔断器实现了服务的自动降级,让微服务具备自我保护的能力,提升了系统的稳定性,比较好的解决雪崩效应。其使用方式目前支持两种策略:
- 线程池隔离策略:使用一个线程池来存储当前的请求,线程池对请求做处理,设置任务返回处理超时时间,堆积的请求堆积入线程池队列。这种方式需要为每个依赖的服务申请线程池,有一定的资源消耗,好处是可以应对突发流量(流量洪峰来临时,处理不完可将数据缓存到线程池队列里慢慢处理)
- 信号量隔离策略:使用一个原子计数器(或信号量)来记录当前有多少个线程在运行,请求来先判断计数器的数值,若超过设置的最大线程个数则丢弃该类型的新请求,若不超过则执行计数操作请求来计数器+1,请求返回计数器-1。这种方式是严格的控制线程且立即返回模式,无法应对突发流量(流浪洪峰来临时,处理的线程超过数量,其他的请求会直接返回,不继续去请求依赖的服务)
线程池和信号量两种策略功能支持对比:

配置策略:
- hystrix.command.default.execution.isolation.strategy: #配置隔离策略
- ExecutionIsolationStrategy.SEMAPHORE #信号量隔离
- ExecutionIsolationStrategy.THREAD #线程池隔离
- hystrix.command.default.execution.isolation.maxConcurrentRequests:最大信号量上限
hystrix执行过程

Sentinel组件
1、概述
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。
sentinel具有以下特征
- 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
- 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
- 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
- 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
名词解释
Sentinel 分为两个部分:
- 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
- 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。
使用sentinel进行熔断保护,主要分为几个步骤:
1. 定义资源
2. 定义规则
3. 检验规则是否生效
资源
资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。
只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。
规则
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整
sentinel主要特性
功能对比
| Sentinel | Hystrix | resilience4j | |
|---|---|---|---|
| 隔离策略 | 信号量隔离(并发线程数限流) | 线程池隔离/信号量隔离 | 信号量隔离 |
| 熔断降级策略 | 基于响应时间、异常比率、异常数 | 基于异常比率 | 基于异常比率、响应时间 |
| 实时统计实现 | 滑动窗口(LeapArray) | 滑动窗口(基于 RxJava) | Ring Bit Buffer |
| 动态规则配置 | 支持多种数据源 | 支持多种数据源 | 有限支持 |
| 扩展性 | 多个扩展点 | 插件的形式 | 接口的形式 |
| 基于注解的支持 | 支持 | 支持 | 支持 |
| 限流 | 基于 QPS,支持基于调用关系的限流 | 有限的支持 | Rate Limiter |
| 流量整形 | 支持预热模式、匀速器模式、预热排队模式 | 不支持 | 简单的 Rate Limiter 模式 |
| 系统自适应保护 | 支持 | 不支持 | 不支持 |
| 控制台 | 提供开箱即用的控制台,可配置规则、查看秒级监控、机器发现等 | 简单的监控查看 | 不提供控制台,可对接其它监控系统 |
hystrix迁移方案
| Hystrix 功能 | 迁移方案 |
|---|---|
| 线程池隔离/信号量隔离 | Sentinel 不支持线程池隔离;信号量隔离对应 Sentinel 中的线程数限流,详见此处 |
| 熔断器 | Sentinel 支持按平均响应时间、异常比率、异常数来进行熔断降级。从 Hystrix 的异常比率熔断迁移的步骤详见此处 |
| Command 创建 | 直接使用 Sentinel SphU API 定义资源即可,资源定义与规则配置分离,详见此处 |
| 规则配置 | 在 Sentinel 中可通过 API 硬编码配置规则,也支持多种动态规则源 |
| 注解支持 | Sentinel 也提供注解支持,可以很方便地迁移,详见此处 |
| 开源框架支持 | Sentinel 提供 Servlet、Dubbo、Spring Cloud、gRPC 的适配模块,开箱即用;若之前使用 Spring Cloud Netflix,可迁移至 Spring Cloud Alibaba |
2、sentinel管理控制台
2.1 概述:
Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。另外,鉴权在生产环境中也必不可少。
Sentinel 控制台包含如下功能:
- 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。
- 监控 (单机和集群聚合):通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。
- 规则管理和推送:统一管理推送规则。
- 鉴权:生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。
2.2 启动控制台
2.2.1 获取sentinel控制台
可以从 release 页面 下载最新版本的控制台 jar 包。
您也可以从最新版本的源码自行构建 Sentinel 控制台:
- 下载 控制台 工程
- 使用以下命令将代码打包成一个 fat jar:
mvn clean package
2.2.2 启动
注意:启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本。
使用命令启动控制台:
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
其中 -Dserver.port=8080 用于指定 Sentinel 控制台端口为 8080。
从 Sentinel 1.6.0 起,Sentinel 控制台引入基本的登录功能,默认用户名和密码都是 sentinel。可以参考 鉴权模块文档 配置用户名和密码。
2.2.3 客户端接入控制台
控制台启动后,客户端需要按照以下步骤接入到控制台。
2.3.1 引入jar包
客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信。您可以通过 pom.xml 引入 JAR 包:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>x.y.z</version>
</dependency>
2.3.2 配置启动参数
启动时加入 JVM 参数 -Dcsp.sentinel.dashboard.server=consoleIp:port 指定控制台地址和端口。若启动多个应用,则需要通过 -Dcsp.sentinel.api.port=xxxx 指定客户端监控 API 的端口(默认是 8719)。
从 1.6.3 版本开始,控制台支持网关流控规则管理。您需要在接入端添加 -Dcsp.sentinel.app.type=1 启动参数以将您的服务标记为 API Gateway,在接入控制台时您的服务会自动注册为网关类型,然后您即可在控制台配置网关规则和 API 分组。
除了修改 JVM 参数,也可以通过配置文件取得同样的效果。更详细的信息可以参考 启动配置项。
2.3.3 触发客户端初始化
确保客户端有访问量,Sentinel 会在客户端首次调用的时候进行初始化,开始向控制台发送心跳包。
注意:您还需要根据您的应用类型和接入方式引入对应的 适配依赖,否则即使有访问量也不能被 Sentinel 统计。
3、使用sentinel组件
3.1、管理控制台
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
启动成功 localhost:8080/
访问的用户名/密码:sentinel/sentinel
3.2、将所有的服务交给控制台管理
客户端接入Sentinel管理控制台
在客户端(需要管理微服务上)引入坐标
父项目引入坐标:
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency>子项目引入坐标:
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>2.2.0.RELEASE</version> </dependency>在客户端配置启动参数
sentinel: transport: dashboard: localhost:8080 #sentinel 控制中心ip:portsentinel默认为懒加载,启动以后需要访问资源路径才能在管理控制台查看到监控信息。
3.3 通用资源保护
/**
* blockHandler:声明熔断时的限流方法(在抛出BlockException异常是触发,限流方法的参数需要添加BlockException)
* fallback:抛出异常时的降级方法
* value:自定义资源名称(默认为当前全类名.方法名)
*/
@SentinelResource(value = "getUserBalanceById",fallback = "userFallBack",blockHandler = "userBlockHandler")
@GetMapping("/getUserBalanceById/{id}")
public User getUserBalanceById(@PathVariable Long id) throws MyException {
if(id!=26){
throw new MyException("error");
}
String url = "http://localhost:8001/user/getUserById/"+id;
//根据服务注册名称获取服务实例列表
url = "http://user-service/user/getUserById/"+id;
return restTemplate.getForObject(url,User.class);
}
/**
* 定义降级逻辑
* sentinel和hystrix不同
* 可以指定熔断执行的降级方法
* 可以指定抛出异常执行的降级方法
*/
public User userBlockHandler(Long id, BlockException e){
User user = new User();
user.setName("断了");
user.setId(id);
return user;
}
public User userFallBack(Long id){
User user = new User();
user.setName("异常");
user.setId(id);
return user;
}
3.4 RestTemplate的资源保护
启动类配置@SentinelRestTemplate
/**
* sentinel支持对RestTemplate的服务调用使用sentinel方法.
* 在构造RestTemplate对象的时候,只需要加载@SentinelRestTemplate即可
*
* @SentinelRestTemplate
* blockHandler :限流方法
* blockHandlerClass:限流配置类
* fallback :降级方法
* fallbackClass :降级配置类
*
* 资源名:
* httpmethod:schema://host:port/path 协议://主机:端口/路径
* httpmethod:schema://host:port 协议://主机:端口
*/
//使用@LoadBalanced注解实现负载均衡
@Bean
@LoadBalanced
@SentinelRestTemplate(fallbackClass = ExceptionUtils.class,fallback = "handlerFallback",
blockHandlerClass = ExceptionUtils.class,blockHandler = "handlerBlock")
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
编辑通用降级逻辑
public class ExceptionUtils {
/**
* 静态方法
* 返回值:SentinelClientHttpResponse
* 参数:HttpRequest,byte[],ClientHttpRequestExecution,BlockException
*/
//异常降级业务逻辑
public static SentinelClientHttpResponse handlerFallback(HttpRequest request, byte[] body,
ClientHttpRequestExecution execution,
BlockException exception) {
System.out.println("fallback" + exception.getClass().getCanonicalName());
User user = new User();
user.setName("异常熔断降级");
return new SentinelClientHttpResponse(JSON.toJSONString(user));
}
//限流熔断业务逻辑
public static SentinelClientHttpResponse handlerBlock(HttpRequest request, byte[] body,
ClientHttpRequestExecution execution,
BlockException exception) {
System.out.println("block" + exception.getClass().getCanonicalName());
User user = new User();
user.setName("限流熔断降级");
return new SentinelClientHttpResponse(JSON.toJSONString(user));
}
}
3.5 Feign实现熔断
Sentinel适配了Feign组件。如果想使用,除了引入sentinel-starter的依赖外还需要2个步骤:
- 配置文件打开sentinel对feign的支持:
feign.sentinel.enabled=true - 加入openfeign starter依赖是sentinel starter中的自动化配置类生效
引入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>2.2.2.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>2.2.1.RELEASE</version> </dependency>开启sentinel支持
在工程的application.yml中添加sentinel对feign的支持
feign: sentinel: enabled: true配置FeignClient(与使用Hystrix类似)
声明fallback对应的处理类
/** * 声明需要调用的微服务名称 * name:服务提供者的名称 */ @FeignClient(name = "USER-SERVICE",fallback = UserFeignClientCallBack.class) public interface UserFeignClient { //配置需要调用的微服务接口 @RequestMapping(value = "/user/getUserById/{id}", method = RequestMethod.GET) User getUserById(@PathVariable("id") Long id); }配置熔断降级方法
@Component public class UserFeignClientCallBack implements UserFeignClient{ /** * 熔断降级的方法 */ public User getUserById(Long id) { User user = new User(); user.setName("降级"); return user; } }
4、sentinel加载本地设置
一条限流规则以下几个因素组成:
resource:资源名,即限流规则的作用对象
count:限流阈值
grade:限流阈值类型(QPS或并发线程数)
limitApp:流控针对的调用来源,若为default则不区分调用来源
strategy:调用关系限流策略
controlBehavior:流量控制效果(直接拒绝、WarmUp、匀速排队)
Java代码 RuleConstant
配置文件添加如下配置
#通过文件读取限流规则
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080
datasource:
ds1:
file:
file: classpath:flowrule.json
data-type: json
rule-type: flow
flowjson内容:
[
{
"resource": "getUserBalanceById",
"controlBehavior": 0,
"count":1,
"grade":1,
"limitApp": "default",
"strategy": 0
}
]