Hystrix与Geteway简介
前言
Hystrix(英文含义:豪猪)由Netflix公司开发的,后来由Spring Cloud Hystrix基于这款框架实现了断路器、线程隔离等一系列服务保护功能,该框架的目标在于通过控制访问远程系统、服务和第三方库的节点,从而延迟和故障提供更强大的容错能力。
Hystrix具备服务降级、服务熔断、线程和信号隔离、请求缓存、请求合并以及服务监控等强大功能。是一种微服务的保护机制。
Hystrix防止某个单元出现故障.从而引起依赖关系引发故障的蔓延,最终导致整个系统的瘫痪。
Spring Cloud Gateway 里明确的区分了 Router 和 Filter,并且一个很大的特点是内置了非常多的开箱即用功能,并且都可以通过 SpringBoot 配置或者手工编码链式调用来使用。
提示:以下是本篇文章正文内容,下面案例可供参考
一、服务降级
服务降级:服务器忙碌或者网络拥堵时,不让客户端等待并立刻返回一个友好提示,fallback(备选方案)。
场景:调用服务超时,服务本身 内部错误,服务的线程资源耗尽
1.局部服务降级
1.1 在服务提供方设置
在服务提供方进行局部服务设置,首先设置自身调用超时的峰值,峰值内正常运行,超出峰值需要有兜底的方法处理,作服务降级fallback调用。
(1)引入Hystrix依赖
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
(2)在service中对超时方法进行设置,访问超时调用兜底方法
( 降级方法(逻辑)编写的原则是方法的形参和返回值必须要和被降级的方法保持一致。)
/**
超时访问的方法,添加@HystrixCommand注解
*/
@HystrixCommand(fallbackMethod = "timeoutHandler",commandProperties = {
//设置峰值,超过 3 秒,就会调用兜底方法,这个时间也可以由feign控制
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
public String paymentInfo_Timeout(Integer id){
//设置超时调用时间
int interTime = 5;
//int i = 10/0;
try{
TimeUnit.SECONDS.sleep(interTime);
}catch (Exception e){
e.printStackTrace();
}
return "线程池:" + Thread.currentThread().getName() + " ,paymentInfo_Timeout,id:" + id + "耗时" + interTime + "秒钟";
}
// 定义服务出现异常之后,兜底的方法
//降级方法(逻辑)编写的原则是方法的形参和返回值必须要和被降级的方法保持一致。
public String timeoutHandler(Integer id){
return "服务异常,请重试......";
}
}
(3)在启动类上加上@EnableCircuitBreaker 作用:开启服务熔断
(4)运行测试结果
(5)同样在service的方法中设置一个异常(替换上一步的超时设置),用于模拟测试
public String paymentInfo_Timeout(Integer id){
//int interTime = 5;
//定义一个异常,用于测试
int i = 10/0;
}
(6)测试结果。
在发生服务不可用(调用超时或方法内部异常)时,都会进行降级调用来处理问题。
1.2 在消费方设置
(1)首先取消上述对于服务提供方的降级调用设置
(2)引入Hystrix依赖
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
(3)在启动类上加上@EnableCircuitBreaker 作用:开启服务熔断
(4) 在controller层设置服务降级的逻辑编写,访问超时调用兜底方法
@HystrixCommand(fallbackMethod = "handeException", commandProperties = {
//设置峰值,超过 1.5 秒,就会调用兜底方法
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value = "1500")
})
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
public String paymentInfo_Timeout(@PathVariable("id")Integer id){
log.info("paymentInfo_timeout");
return orderService.paymentInfo_Timeout(id);
}
//定义兜底方法
public String handeException(Integer id){
return "服务调用异常,请稍后再试.....";
}
(5)运行测试结果
(6)在服务提供方的service的方法中设置一个异常,返回一个值,用于测试结果
public String paymentInfo_Timeout(Integer id){
//设置超时调用时间
//int interTime = 5;
//定义异常
int i = 10/0;
/*try{
TimeUnit.SECONDS.sleep(interTime);
}catch (Exception e){
e.printStackTrace();
}
return "线程池:" + Thread.currentThread().getName() + " ,paymentInfo_Timeout,id:" + id + "耗时" + interTime + "秒钟";*/
return "发生内部异常";
}
2.全局服务降级
(1)全局服务降级
1.在消费方的启动类上面要加上一个@EnableCircuitBreaker
2.在消费方的controller里面,定义一个全局降级的方法。
//全局服务降级处理在服务消费方上面实现
// 全局降级处理方法
public String globalHandler(){
return "这是全局处理降级逻辑的方法.......";
}
3.在controller上面 添加一个注解@DefaultProperties(defaultFallback = “handleAll”)
4.在指定的被降级的方法上添加一个@HystrixCommand
@RestController
@Slf4j
@DefaultProperties(defaultFallback = "globalHandler") //开启全局降级处理
public class OrderController {
@Autowired
OrderService orderService;
@HystrixCommand //不写fallbackMethod属性,默认是全局
@GetMapping("/consumer/payment/hystrix/timeout/{id}") //服务超时
public String paymentInfo_Timeout(@PathVariable("id")Integer id){
log.info("paymentInfo_timeout");
return orderService.paymentInfo_Timeout(id);
}
}
注意:降级逻辑的优先级 局部的降级逻辑>全局的降级逻辑
(2)服务降级方法抽取
- 在消费方的启动类上面要加上一个@EnableCircuitBreaker
- 在配置文件里面,开启feign对Hystrix的支持
feign:
hystrix:
enabled: true
- 定义一个类,实现Feign客户端。重写里面的方法(编写降级处理方法)
@Component
public class FallBackService implements OrderService {
@Override
public String paymentInfo_OK(Integer id) {
return "进行paymentInfo_OK方法降级处理......";
}
@Override
public String paymentInfo_Timeout(Integer id) {
return "进行paymentInfo_Timeout方法降级处理";
}
}
- 使用@FeignClient注解,将这个类绑定到Feign客户端上去
@Component
@FeignClient(value = "cloud-payment-service",fallback = FallBackService.class)
public interface OrderService {
@GetMapping("/payment/hystrix/{id}")
public String paymentInfo_OK(@PathVariable("id")Integer id);
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_Timeout(@PathVariable("id")Integer id);
}
- 进行测试,查看降级处理结果
二、服务熔断
代码如下(示例):
1.服务熔断的概述
当用户访问某个服务,达到了最大的访问量之后,直接拒绝用户访问。
在SpringCloud框架中,熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况。当失败的调用到一定阈值时,缺省是5秒内20次调用失败,就会启动熔断机制。熔断机制的注解是@HystrixCommand。
2.熔断有哪几种状态
熔断状态机3个状态:
(1)Closed:关闭状态,所有请求都正常访问。
(2)Open:打开状态,所有请求都会被降级。Hystix会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全打开。默认失败比例的阈值是50%,请求次数最少不低于20次。
(3)Half Open:半开状态,open状态不是永久的,打开后会进入休眠时间(默认是5S)。随后断路器会自动进入半开状态。此时会释放部分请求通过,若这些请求都是健康的,则会完全关闭断路器,否则继续保持打开,再次进行休眠计时。
3.断路器的工作原理
统计用户在指定的时间范围(默认10s)之内的请求总数达到指定的数量之后,如果不健康的请求(超时、异常)占总请求数量的百分比(50%)达到了指定的阈值之后,就会触发熔断。触发熔断后,断路器就会打开(open),此时所有请求都不能通过。在5s之后,断路器会恢复到半开状态(half open),会允许少量请求通过,如果这些请求都是健康的,那么断路器会回到关闭状态(close).如果这些请求还是失败的请求,断路器还是恢复到打开的状态(open)。
4.如何开启熔断?
1.在指定请求方法上,开启熔断
@HystrixCommand(fallbackMethod = "handleCircuitBreaker",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"), // 失败率达到多少后跳闸
//整体意思:10秒内 10次请求,有6次失败,就跳闸
})
public String enableCircuitBreaker(Integer id){
if(id < 0){
throw new RuntimeException();
}
String uuid = UUID.randomUUID().toString();
return "返回的uuid是:" + uuid;
}
2.使用XML的方式进行熔断的配置
#全局服务降级,feign+hystrix整合,即 service 实现类的方式做全局配置?
hystrix:
command:
default:
circuitBreaker:
enabled: true
requestVolumeThreshold: 10
sleepWindowInMilliseconds: 10000
errorThresholdPercentage: 60
三、Hystrix DashBoard
除了隔离依赖服务的调用以外,Hystrix还提供了
准时调用监控(Hystrix DashBoard)
,Hystrix 会持续地记录所有通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少请求多少成功,多少失败等。
Netflix通过hystrix-metrics-event-stream项目实现了对以上指标的指控。SpringCloud也提供了Hystrix Dashboard的整合,对监控内容转化为可视化界面。
1.创建仪表盘监控模块
(1)在项目中创建仪表盘监控模块
(2)编写启动类,使用@EnableHystrixDashboard注解开启仪表盘监控
@SpringBootApplication
@EnableHystrixDashboard //开启仪表盘监控
public class HystrixDashboardApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardApplication.class,args);
}
}
(3)编写配置文件
server:
port: 9001 #端口号,自定义
(4)引入依赖
注意:所有被监控的服务都需要添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
(5)启动测试:访问 http://localhost:9001/hystrix
2. 监控实战
(1)在http://localhost:9001/hystrix页面中访问http://localhost:8001/hystrix.stream
(2)访问:http://localhost:8001/payment/circuit/1 ,请求数据
查看请求量等信息。
类如下图所示:
四、Geteway网关
1.Geteway网关简介
Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代ZUUL,其不仅提供统一的路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等。
2.Gateway 的核心概念
三大核心概念:
(1)路由(Route):路由是网关的基本模块,由ID,目标URL,一系列的断言和过滤器组成。断言为真,则路由匹配。
(2)断言(Predicate):输入类型是一个ServerWebExchange。开发人员可以使用它匹配HTTP请求中的任何内容,例如headers或参数。如果请求和断言相匹配,则进行路由。
(3)过滤(Filter):Gateway中的Filter分为两种类型,分别是Gateway Filter和Global Filter。过滤器可以在请求被路由前或之后
对请求进行修改。
3.如何简单使用gateway(入门案例)
(1)创建gateway模块
(2)引入POM依赖
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--eureka-client gateWay作为网关,也要注册进服务中心-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- gateway和web不能同时存在,即web相关jar包不能导入 -->
(2)编写application.yml配置文件
server:
port: 9527
spring:
application:
name: cloud-gateway
## GateWay配置
cloud:
gateway:
discovery:
locator:
enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh # 路由ID , 没有固定的规则但要求唯一,建议配合服务名
uri: lb://cloud-payment-service # 匹配后提供服务的路由地址,之前http://localhost:8001,换成
predicates:
- Path=/payment/** # 断言,路径相匹配的进行路由
- id: payment_routh2 # 路由ID , 没有固定的规则但要求唯一,建议配合服务名
uri: lb://cloud-payment-service # 匹配后提供服务的路由地址,之前localhost:8001,cloud-payment-service
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由,lb 属于GateWay 的关键字,代表是动态uri,即代表使用的是服务注册中心的微服务名,它默认开启使用负载均衡机制
# 在这个时间之后失效
#- After=2021-01-18T21:08:21.474+08:00[GMT+08:00]
#- Before=2021-01-18T21:08:21.474+08:00[GMT+08:00]
#- Between=2021-01-18T21:08:21.474+08:00[GMT+08:00],2021-01-18T22:08:21.474+08:00[GMT+08:00]
# 注册进 eureka Server
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
register-with-eureka: true
fetch-registry: true
(3)创建启动类
@SpringBootApplication
@EnableEurekaClient
public class GatewayMain9527 {
public static void main(String[] args) {
SpringApplication.run(GatewayMain9527.class,args);
}
}
(4)测试结果
可使用网关端口调用业务逻辑,隐藏了业务微服务端口,使用网关服务对微服务进行保护。
4.通过微服务名实现动态路由
默认情况下,Getway会根据注册中心的服务列表,以注册中心上的微服务名为路径创建动态路由进行转发,从而实现动态路由的功能。
所谓的动态配置就是利用服务注册中心,来实现负载均衡的调用多个微服务。这是GateWay 的负载均衡。
(1)设置配置文件
server:
port: 9527
spring:
application:
name: cloud-gateway
## GateWay配置
cloud:
gateway:
discovery:
locator:
enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh # 路由ID , 没有固定的规则但要求唯一,建议配合服务名
uri: lb://cloud-payment-service # 匹配后提供服务的路由地址
predicates:
- Path=/payment/** # 断言,路径相匹配的进行路由
- id: payment_routh2 # 路由ID , 没有固定的规则但要求唯一,建议配合服务名
uri: lb://cloud-payment-service # 匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
# 注册进 eureka Server
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
register-with-eureka: true
fetch-registry: true
注意:
uri: lb://CLOUD-PROVIDER-SERVICE 解释:lb 属于GateWay 的关键字,代表是动态uri,即代表使用的是服务注册中心的微服务名,它默认开启使用负载均衡机制
(2)测试发现实现负载均衡
5.断言Predicate
Predicate(断言) 就是进行条件判断, 判断在什么条件下 才能进行路由转发,只有断言都返回真,才会真正的执行路由。
断言工厂的分类:
在配置文件中定义断言
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由,lb 属于GateWay 的关键字,代表是动态uri,即代表使用的是服务注册中心的微服务名,它默认开启使用负载均衡机制
# 在这个时间之后失效
#- After=2021-01-18T21:08:21.474+08:00[GMT+08:00]
# 在这个时间之前失效
#- Before=2021-01-18T21:08:21.474+08:00[GMT+08:00]
# 在这个时间段之间失效
#- Between=2021-01-18T21:08:21.474+08:00[GMT+08:00],2021-01-18T22:08:21.474+08:00[GMT+08:00]
6.Filter
今天在这里简单分享一下自定义全局过滤器:
(1)自定义一个全局过滤器类,继承GlobalFilter,Ordered接口,并重写其方法。
@Component
@Slf4j
public class GateWayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String username = exchange.getRequest().getQueryParams().getFirst("username");
if(username == null){
log.info("用户名为null,请求不能通过......");
exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
//完成请求调用
return exchange.getResponse().setComplete();
}
return chain.filter(exchange); //放行
}
@Override
public int getOrder() {
return 0; //过滤器执行的优先级,数字越小 优先级越高
}
}
(2)测试过滤器效果,
注意:请求url必须携带username参数,否则不允许通过
总结
以上就是今天分享的内容,本文仅仅简单介绍了Hystrix与Gateway网关的相关内容及使用。