目录
5.2.4、 访问http://localhost:9001/hystrix,得到以下页面
5.3.1、填写监控地址 http://localhost:8001/hystrix.stream
5.3.2、多次调用微服务,并在监控界面打开Monitor stream
1、概念
1.1、分布式系统面临的问题
1.分布式体系结构中的应用程序,有数10个依赖关系,每个依赖关系在某些时候将不可避免的失败
2.服务雪崩:
-
多个微服务之间调用时,假设微服务A调用微服务B和C,B和C又调用其他微服务,即“
扇出
”。 -
扇出的链路上某个微服务的调用响应时间过长或不可用,对A的调用会占用越来越多的系统资源,进而引起系统崩溃(级联故障),即“
雪崩效应
”
1.2、Hystrix是什么
1.Hystrix是一个用于处理分布式系统的
延迟
和
容错
的开源库
2.Hystrix能够保证在一个依赖出问题的情况下,
不会导致整体服务失败,避免级联故障,提高分布式系统弹性
3.Hystrix作为“断路器”,当某个服务单元发生故障时,通过断路器的故障监控,
向调用方返回一个符合预期的、可处理的备选响应(FallBack)
,而不是长时间的等待或抛出调用方无法处理的异常。从而避免雪崩。
1.3、Hystrix作用
1.服务降级(FallBack):服务器忙时,不让客户端等待并立刻返回一个友好提示。
发生情况:程序运行异常、超时、服务熔断触发服务降级、线程池/信号量也会导致服务降级
2.服务熔断(Break):达到最大服务访问后,直接拒绝访问,调用服务降级方法并返回友好提示
3.接近实时的监控(FlowLimit):秒杀高并发等,严禁一窝蜂的过来拥挤,一秒钟N个,有序进行
1.4、Hystrix工作流程
1、构造一个HystrixCommand或HystrixObservableCommand对象,用于封装请求
2、执行命令,Hystrix提供了4种执行命令的方法;
3、判断是否使用缓存响应请求,若启用了缓存,且缓存可用,直接使用缓存响应请求。
4、判断熔断器是否打开,如果打开,跳到第8步;
5、判断线程池/队列/信号量是否已满,已满则跳到第8步;
6、执行HystrixObservableCommand.construct()或HystrixCommand.run(),如果执行失败或者超 时,跳到第8步;否则,跳到第9步;
7、统计熔断器监控指标;
8、走Fallback备用逻辑;
9、返回请求响应。
2、Hystrix案例
2.1、构建正常微服务(服务提供者)
controller:提供两项,url映射规则
@RestController
@Slf4j
public class PaymentController {
@Resource
private PaymentService paymentService;
@Value("${server.port}")
private String serverPort;
@GetMapping("/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id){
String result = paymentService.paymentInfo_OK(id);
log.info("result:" + result);
return result;
}
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
String result = paymentService.paymentInfo_TimeOut(id);
log.info("result:" + result);
return result;
}
}
2.2、压力测试
2.2.1、Jmeter压测测试
2.2.2、客户端压测测试
service:调用2.1中提供的微服务接口
@Component
@FeignClient(value = "Provider-hystrix-payment")
public interface OrderHystrixService {
@GetMapping("/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id);
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_TimeOut(@PathVariable("id") Integer id);
}
3、解决方案
3.1、服务降级
- 设置自身调用超时时间的峰值,峰值内可以正常运行
- 超过了需要有兜底的方法处理,做服务降级fallback
3.1.1、服务端微服务降级
1.POM文件:添加 hystrix 开发场景
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2.业务类:@HystrixCommand 声明兜底逻辑
兜底业务逻辑,针对超时异常,计算异常(int i= 10/0)均可进行兜底
@Service
public class PaymentService {
//注解中声明paymentInfo_TimeOutHandler方法为兜底业务逻辑,
//同时声明该业务逻辑的正常执行时长为3秒钟以内
@HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",
commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")})
public String paymentInfo_TimeOut(Integer id) {
int timeNumber = 10;
try{
TimeUnit.SECONDS.sleep(timeNumber);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "线程池:" + Thread.currentThread().getName() + "paymentInfo_TimeOut,id:" + id + "\t";
}
//兜底业务逻辑
public String paymentInfo_TimeOutHandler(Integer id) {
return "线程池:" + Thread.currentThread().getName() + "paymentInfo_TimeOutHandler,id:" + id + "\t";
}
}
3.主启动类:添加 @EnableCircuitBreaker 激活
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class PaymentHystrixMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentHystrixMain8001.class, args);
}
}
3.1.2、客户端微服务降级
1. POM文件:添加 hystrix 开发场景
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2. yaml配置文件:开启Hystrix服务降级
#开启hystrix
feign:
hystrix:
enabled: true
3.主启动类:添加 @EnableHystrix 激活 Hystrix
@SpringBootApplication
@EnableFeignClients
@EnableHystrix
public class OrderHystrixMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderHystrixMain80.class, args);
}
}
4.业务类:声明兜底逻辑
@HystrixCommand
(fallbackMethod = ”
paymentTimeOutFallbackMethod
“, commandProperties = {@HystrixProperty(name = “execution.isolation.thread.timeoutInMilliseconds”, value = “1500”)})
@RestController
@Slf4j
public class OrderHystrixController {
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
@HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
})
public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
return orderHystrixService.paymentInfo_TimeOut(id);
}
public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
return "我是消费者80,对方支付系统繁忙请10秒种后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
}
}
5.测试结果
3.1.3、代码优化
1)每个方法都有兜底会引起代码膨胀(
业务超时
)——客户端微服务代码优化(controller)
除特殊业务逻辑外,针对普通的业务逻辑,可以设计一个通用的兜底方法,并进行全局配置,
防止代码膨胀
1、
@DefaultProperties
(defaultFallback = ”
payment_Global_FallbackMethod
“) 声明兜底方法
2、
@HystrixCommand
被兜底的方法,利用该注解进行标注
3、编写全局兜底逻辑
payment_Global_FallbackMethod
@RestController
@Slf4j
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public class OrderHystrixController {
@Resource
private OrderHystrixService orderHystrixService;
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
@HystrixCommand
public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
return orderHystrixService.paymentInfo_TimeOut(id);
}
//下面是全局fallback方法
public String payment_Global_FallbackMethod() {
return "Global异常处理信息,请稍后重试.o(╥﹏╥)o";
}
}
测试结果:
2)兜底和业务写在一起,代码混乱(
服务端宕机或关闭
)——客户端微服务解耦(service)
1.新建service类,实现service接口
service类
是对服务端微服务的远程调用时,服务端宕机的
兜底逻辑
:
@Component
public class OrderFallbackService implements OrderHystrixService {
@Override
public String paymentInfo_OK(Integer id) {
return "OrderFallbackService fallback, paymentInfo_OK";
}
@Override
public String paymentInfo_TimeOut(Integer id) {
return "OrderFallbackService fallback, paymentInfo_TimeOut";
}
}
2.service 接口,
@FeignClient
注解,添加
fallback
属性
service接口是对服务端接口的远程调用,需要在
@FeignClient
注解中
添加 fallback = OrderFallbackService.class
,声明该 service 类是该远程调用接口的兜底逻辑
@Component
@FeignClient(value = "Provider-hystrix-payment", fallback = OrderFallbackService.class)
public interface OrderHystrixService {
@GetMapping("/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id);
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_TimeOut(@PathVariable("id") Integer id);
}
3.配置 yaml 文件,开启Hystrix功能
#开启hystrix
feign:
hystrix:
enabled: true
4、测试:依次开启,Eureka服务端、服务端微服务、客户端微服务,并在手动关闭服务端微服务前后,调用客户端url接口,进行服务端远程调用,查看结果。
4、服务熔断
4.1、熔断概念
熔断机制
是应对雪崩效应的一种微服务
链路保护机制
,当扇出链路的某个微服务出错不可用或者响应时间太长时,会进行
服务的降级
,
进而熔断
该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务
调用响应正常
后,
恢复
调用链路。
4.2、熔断实操(服务端微服务)
4.2.1、service层
1.在被熔断的业务逻辑上添加 @HystrixCommand 注解:
1)声明熔断后的兜底逻辑
2)设置熔断参数
2.添加 paymentCircuitBreaker_fallback 熔断兜底逻辑
@Service
public class PaymentService {
/** 服务熔断 */
//表示在时间窗口期中10次请求有6次是错误的,就有调用断路器
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback", 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"),
})
public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
if(id < 0){
throw new RuntimeException("id,不能为负数");
}
String serialNumber = IdUtil.simpleUUID();
return Thread.currentThread().getName() + "\t" + "调用成功,流水号:" + serialNumber;
}
public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id) {
return "id不能为负数,请稍后再试,/(ToT)/~~ id:" + id;
}
}
4.2.2、controller层
@RestController
@Slf4j
public class PaymentController {
@Resource
private PaymentService paymentService;
@Value("${server.port}")
private String serverPort;
@GetMapping("/payment/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
String result = paymentService.paymentCircuitBreaker(id);
log.info("result:" + result);
return result;
}
}
4.3、 熔断原理
4.3.1、熔断类型
1)熔断打开:请求不再调用当前服务,内部设置一般为MTTR(平均故障处理时间),
当打开时间到达所设时长,则进入半熔断状态。
2)熔断关闭:熔断关闭后不会对服务进行熔断。
3)熔断半开:部分请求根据规则调用当前服务,如果请求成功且符合规则,
则认为当前服务恢复正常,关闭熔断。
4.3.2、断路器流程
1)断路器开启设置:快照时间窗、请求总数阈值、错误百分比阈值
快照时间窗:即统计的时间范围,断路器是否打开需要统计请求和错误数据(默认10s)
请求总数阈值:在快照时间窗内,必须满足请求总数阈值,才有资格熔断(默认20)
错误百分比阈值:请求总数超过阈值时,响应错误占比达到阈值时断路器打开(默认50%)
2) 断路器运行流程:
- 当请求总数及失败率满足一定的阈值的时候,断路器开启
- 当开启的时候,所有请求都不会进行转发
-
一段时间之后(默认5秒),断路器转为半开状态,会让其中一个请求进行转发.:
- 如果成功,断路器会关闭
- 若失败,继续开启
3)断路器打开之后:
再有请求的时候,将不会调用主逻辑,而是直接调用降级 fallback。通过断路器,实现了自动地发现错误,并将降级逻辑切换为主逻辑,减少响应延迟的效果。
5、服务监控Hystrix Dashboard
5.1、Hystrix Dashboard概述
Hystrix 提供了准实时的调用监控(Hystrix Dashboard),Hystrix 会持续地记录所有通过 Hystrix 发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括执行多少请求,多少成功、失败等。Spring Cloud也提供了 Hystrix Dashboard 的整合,将监控内容转化成可视化界面。
5.2、Hystrix Dashboard服务搭建
5.2.1、POM文件:
添加 hystrix-dashboard 开发场景
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
5.2.2、 配置yaml文件(端口号)
server:
port: 9001
5.2.3、编写主启动类
添加 @EnableHystrixDashboard 注解,激活 Hystrix Dashboard 组件。
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashBoardMain9001 {
public static void main(String[] args) {
SpringApplication.run(HystrixDashBoardMain9001.class, args);
}
}
5.2.4、 访问http://localhost:9001/hystrix,得到以下页面
5.3、断路器演示(9001监控8001)
5.3.1、填写监控地址 http://localhost:8001/hystrix.stream
5.3.2、多次调用微服务,并在监控界面打开Monitor stream
1)查看监控结果:
2)监控指标说明: