官网停更说明
官网:https://github.com/Netflix/Hystrix
Hystrix目前已经停更进入维护阶段:(代替品:Spring cloud Alibaba Sentinel)
不过Hystrix的设计和思想理念非常好,任然值得一探究竟
基本介绍
分布式系统所面临的问题
服务雪崩
Hystrix是什么
Hystrix几个概念介绍
-
服务降级
服务提供者的服务器忙,不让客户端等待,并立刻返回一个友好提示,fallback发生服务降级的几种情况:
- 程序运行异常
- 超时
- 服务熔断触发服务降级
- 线程池/信号量打满也会导致服务降级
-
服务熔断
类比保险丝,达到最大的访问量后,直接拒绝访问,拉闸限电,然后调用服务降级的方法返回友好提示服务降级->进而熔断 ->恢复调用链路 (具有恢复功能)
-
服务限流
秒杀高并发等操作,严禁一窝蜂过来拥挤,大家排队,一秒N个,有序进行
Hystrix服务降级
服务降级主要解决的问题:
超时导致服务器变慢,----------> 超时不在等待
出错(宕机或者程序运行出错)-------> 返回友好提示
- 服务提供者超时了,服务调用者不能一直卡死等待,必须有服务降级
- 服务提供者者宕机了,服务调用者不能一直等待卡死,必须有服务降级
- 服务提供者OK,调用者自己出故障或者有自我要求(自己等待时间小于服务提供者处理的时间),自己降级处理
Hystrix服务降级配置
服务降级配置一般配置在服务的调用者,当然服务的提供者者也可以配置,具体看业务场景
先添加依赖:
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
主启动类激活注解@EnableCircuitBreaker
@EnableCircuitBreaker
@SpringBootApplication
public class SpringcloudProviderPaymentApplication {
需要服务降级的方法使用注解@HystrixCommand
场景使用:
当一个方法调用设置方法调用超时的时间,设定时间内可以正常运行,调用超过了方法设定的超时时间,则需要有一个兜底方法处理,作为服务降级的fallback(作为备选的响应方法)
@HystrixCommand注解参数解释看注释
// fallbackMethod 兜底方法,降级方法,备用方法
@HystrixCommand(fallbackMethod = "paymentTimeout",commandProperties = {
// 该注解表示对应线程设定的超时时间限制,超过该时间,就调用fallback 降级方法
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1000")
})
@GetMapping("/payment/timeout/get/{id}")
public CommonResult<Payment> getPaymenttimeoutById(@PathVariable("id") Long id) {
// 模拟业务逻辑处理的时间
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Payment payment = paymentService.getPaymentById(id);
return new CommonResult<Payment>(200, port, payment);
}
// 兜底方法,fallback
public CommonResult<Payment> paymentTimeout(Long id) {
return new CommonResult<Payment>(401, "方法调用超时或者出错 ", null);
}
一旦调用服务方法出错抛出异常信息后或者超时,会自动调用@HystrixCommand标注好的fallbackMethod调用类中指定的方法
运行结果:
我们修改下上面的代码,让程序运行不是超时而是运行报错,程序也会自动调用@HystrixCommand标注好的fallbackMethod调用类中指定的方法
@HystrixCommand(fallbackMethod = "paymentTimeout",commandProperties = {
// 该注解表示对应线程设定的超时时间限制,超过该时间,就调用fallback 降级方法
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1000")
})
@GetMapping("/payment/timeout/get/{id}")
public CommonResult<Payment> getPaymenttimeoutById(@PathVariable("id") Long id) {
// 运行报错
int i = 10/0;
Payment payment = paymentService.getPaymentById(id);
return new CommonResult<Payment>(200, port, payment);
}
运行结果:
Hystrix全局服务降级配置
注解:@DefaultProperties(defaultFallback = "")
添加到类上,如果方法上的@HystrixCommand
没有明确指定fallbackMethod
,那么默认就会使用
@DefaultProperties(defaultFallback = "")
指定的fallback
代码示例:
@DefaultProperties(defaultFallback = "globalFallback")
@RestController
public class PaymentController {
// 兜底方法,fallback
public CommonResult<Payment> globalFallback() {
return new CommonResult<Payment>(401, "globalFallback方法调用超时或者出错 ", null);
}
@HystrixCommand
@GetMapping("/payment/timeout/get/{id}")
public CommonResult<Payment> getPaymenttimeoutById(@PathVariable("id") Long id) {
int i = 10/0;
Payment payment = paymentService.getPaymentById(id);
return new CommonResult<Payment>(200, port, payment);
}
运行结果:
Hystrix服务降级配置优化
Hystrix服务降级配置一般情况下都是配置在服务的调用者这边。
-
上述的2种配置都有个问题,服务降级配置和业务逻辑代码混合一起,配置混乱,
-
一般情况下,微服务中,服务的调用者去调用服务的提供者,我们服务降级配置往往只关心 具体服务调用者调用服务的提供者的那些方法。
-
在服务调用者中我们一般可以用Feign客户端调用服务提供者,此时我们只需要为Feign客户端定义的接口 添加一个服务降级处理的实现类即可实现解耦
在服务调用的过程中,我们一般会遇到异常时以下几种:
- 运行时异常
- 服务调用超时
- 服务宕机
优化配置方式:
服务的调用者一般会有Feign客户端定义的接口(文章参考服务调用OpenFeign)
代码如下:
Feign客户端定义的接口:
注意@FeignClient注解上的参数意义
@Component
// 参数1:要调用的微服务名, 参数2:服务降级处理类
@FeignClient(value = "SPRINGCLOUD-PAYMENT-PROVIDER", fallback = OpenFeignPaymentFallBackService.class)
public interface OpenFeignPaymentServer {
@GetMapping("/payment/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
@GetMapping("/payment/timeout/get/{id}")
public CommonResult<Payment> getPaymenttimeoutById(@PathVariable("id") Long id);
}
新建一个类实现Feign客户端定义的接口,统一为接口里面的方法进行异常处理:
@Component
public class OpenFeignPaymentFallBackService implements OpenFeignPaymentServer {
@Override
public CommonResult<Payment> getPaymentById(Long id) {
return new CommonResult<Payment>(401, "getPaymentById方法调用超时或者出错 ", null);
}
@Override
public CommonResult<Payment> getPaymenttimeoutById(Long id) {
return new CommonResult<Payment>(401, "方getPaymenttimeoutById法调用超时或者出错 ", null);
}
}
配置文件YML添加配置:
# 用于服务降级,在注解@FeignClient中添加fallback属性值
feign:
hystrix:
enabled: true # 在Feign中开启Hystrix
有了以上的配置,就不需要再其他任何方法和类上添加关于Hystrix服务降级的任何注解和信息
运行结果:
配置已经生效,当调用服务SPRINGCLOUD-PAYMENT-PROVIDER的方式的时候,如果出现调用异常,那么服务调用者就会调用最后的fallback方法作为作为响应,
Hystrix服务降级总结
在服务调用端有了以上配置(Hystrix服务降级配置优化),就算服务提供者宕机,或者出现各种异常,但是我们做了服务降级处理,让客户端在服务端不可用的时候也会获得提示信息,而不是挂起耗死服务器
Hystrix服务熔断
服务熔断机制是应对雪崩效应的一种服务链路保护机制。当扇出链路的某个微服务出错不可用或者响应世间太长时,会进行服务降级,进而熔断该节点微服务的调用,快速返回错误响应信息 。
当检测到该节点微服务调用响应正常后,恢复调用链路
在Spring Cloud框架里面,熔断机制通过Hystrix实现。Hystrix会监控微服务间的调用状况,当失败的调用到一定阀值时,默认是5秒20次调用失败,就会启动熔断机制。
Hystrix服务熔断配置
下面注解@HystrixProperty 各个参数的说意思:
参数意思是在10秒内请求次数超过10,并且调用错误率达到 60% ,那么该接口就进行熔断,此时就算传入正确的参数,也进行服务降级,待一定时间后,如果会进行一个请求测试,如果可以正常访问,那么熔断器会自动关闭
//=====服务熔断
@HystrixCommand(fallbackMethod = "globalFallback", commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled",value = "true"),// 是否开启断路器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),// 请求次数
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), // 时间窗口期
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),// 失败率达到多少后跳闸
})
@GetMapping("/payment/timeout/get/{id}")
public CommonResult<Payment> getPaymenttimeoutById(@PathVariable("id") Long id) {
if (id < 0) {
throw new RuntimeException("id不能为负数");
}
Payment payment = paymentService.getPaymentById(id);
return new CommonResult<Payment>(200, port, payment);
}
调用结果,当我们输入正数调用的时候,返回正常,
参数传入负数的时候,如果在10秒内,请求次数超过10次,此时错误率已经超过60%,那么服务就会进行熔断,进而服务降级。
Hystrix服务熔断总结
熔断类型:
断路器在什么情况下开始起作用:
断路器开启或者关闭的条件:
断路器打开之后:
Hystrix工作流程图及步骤
工作流程图:
步骤说明:
HystrixDashboard图形界面
HystrixDashboard图形界面搭建步骤:
-
新建一个springboot工程
-
添加依赖 pom依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
-
主启动类添加注解
@EnableHystrixDashboard @SpringBootApplication public class SpringcloudHystrixdashboardApplication {
-
修改端口号
server: port: 9001
-
所有Provider微服务提供服务,都需要添加以下依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
-
启动监控服务
访问地址:http://localhost:9001/hystrix
注意新版本的Hystrix需要在主启动类(被监控的服务的主启动类)上指定路径,如下代码示例:
@EnableDiscoveryClient
@EnableCircuitBreaker
@SpringBootApplication
public class SpringcloudProviderPaymentApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudProviderPaymentApplication.class, args);
}
/**
*此配置是为了服务监控而配置,与服务容错本身无关,springcloud升级后的坑
*ServletRegistrationBean因为springboot的默认路径不是"/hystrix.stream",
*只要在自己的项目里配置上下面的servlet就可以了
*/
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
现在我们用 9001 监控 我们需要监控的服务提供者,
在9001 上添加 需要监控的服务的地址,如下图所示
被监控的服务地址:http://localhost:8003/hystrix.stream
监控如下所示: