微服务系列

1、Nacus 服务搭建及使用
2、Nacos 配置中心
3、Nacos 服务注册与发现之OpenFeign服务间调用
4、Spring Security & Oauth2 认证授权
5、网关(Gateway / Sentinel)路由及熔断限流
6、网关(Gateway自定义断言和过滤器)



前言

之前面试总是碰到面试官对网关Gateway的问题,之前只是用过Netflix的Zuul的路由转发和调用了认证授权服务进行对用户访问的控制,其实Gateway的功能更强,这不周末在吃喝玩乐的闲暇时间,还是需要学习一下才不枉周末时光。

一、Gateway基本介绍?

Gateway见词知意,就是大门的意思,大门呢就是一整个院子的入口,是比较重要的,关系着院内的安全和用户的同一入口引导。
所以Spring Cloud 中的Gateway作为网关的身份担任着重要的角色,常用的功能包括路由转发、权限校验、限流、安全等。
Gateway是Spring Cloud官方推出的第二代网关框架,是有 WebFlux+Netty+Reactor实现的响应式API网关,很好的代替了zuul,有更优秀的性能,更强大的功能。
Gateway对外暴露了统一的访问入口,使得客户端调用后端服务更加方便。

二、核心概念

  • 路由(Route):官方原话是这样说的(The basic building block of the gateway. It is defined by an ID, a destination URI, a collection of predicates, and a collection of filters. A route is matched if the aggregate predicate is true.),就是一个基本构建版块,一个ID, 一个URL,一组断言和一组过滤器组成,如果断言为True,这说明访问的路径合法。
  • 断言(Predicate):官方原话(This is a Java 8 Function Predicate. The input type is a Spring Framework ServerWebExchange. This lets you match on anything from the HTTP request, such as headers or parameters.),断言是 java 8 的断言函数,输入就是一个Spring框架的Web交换机,断言运行开发者自定义匹配HTTP请求里面的任何信息。
  • 过滤器(Filter):官方原话(These are instances of GatewayFilter that have been constructed with a specific factory. Here, you can modify requests and responses before or after sending the downstream request.),就是说,GatewayFilter是为特别的因素构建的,可以对请求之前和响应之后进行处理。GlobalFilter就是全局的过滤器。

三、How it works

Gateway执行原理

四、Gateway服务搭建及路由配置

1、pom依赖

这里没有版本控制,因为上面用了统一的Spring Cloud版本控制器。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

2、application.yml 配置

2.1、路由断言工厂

Gateway 内置了很多路由断言工厂类,在服务启动的时候就会加载,下面是日志。
所以我们服务中直接可以用到这些路由器来实现我们的业务。

Gateway启动日志

2.2、路由断言Path配置

下面的配置,当访问 http://localhost:8088/home-server/api/** 路径是,会转发到 home-server这个服务调用。

server:
  port: 8088 #服务端
spring:
  application:
    name: gateway-server
  #配置gateway
  cloud:
    gateway:
      #路由规则
      routes:
        - id: home-server #路由的唯一标识
          uri: http://localhost:8001
          predicates:
            - Path=/home-server/** #需要断言的路径
          filters:
            - StripPrefix=1 #替换调 home-server实现跳转

访问测试 红框里的 home-server就是要转发的服务。

访问成果

2.3、路由断言工厂After、Before、Between 配置

别的配置不变,只需要在 predicates 下面加上 After 配置就可以限制在配置的时间节点后访问了,这个时间点之前访问不了。
比如下面的配置是 在 2000-08-28 之后才可以访问,今天是 2022-08-27 访问就是 404。

predicates:
...
   - Path=/home-server/** #需要断言的路径
   - After=2022-08-28T22:22:07.783+08:00[Asia/Shanghai]

访问失败

Before 、Between 和 After 一样,需要注意的是配置的时间格式必须是 ZonedDateTime类型的指定日期时间,
这样获取时间

ZonedDateTime zonedDateTime = ZonedDateTime.now();
ZonedDateTime zonedDateTime2 = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));

2.4、路由断言工厂Cookie 配置

Cookie配置则需要在 predicates下面配置上 Cookie 参数即可,在访问的时候就会校验请求头里面的参数。

...
predicates:
   - Path=/home-server/** #需要断言的路径
   - Cookie=username,phen

下面测试结果中,如果 username的是是错误的,则访问失败,把值改了再试一下,见下面的两张结合结果截图。

Cookie的参数错误则不能访问
Cookie的参数正确则可以访问

2.5、路由断言Header配置

predicates:
   - Path=/home-server/** #需要断言的路径
   - Header=Request-Id,\d+ #支持正则

2.6、路由断言 Host 配置

注意:我是在本地配置了 hosts 文件(127.0.0.1 www.text.com)并且网关服务的端口是 80。

...
routes:
 - id: home-server # 路由的唯一标识
   uri: http://localhost:8001
   predicates:
     - Host=**.text.com

2.7、路由断言 Method 配置

只有GET,POST请求才会路由。

...
routes:
   - id: home-server # 路由的唯一标识
     uri: http://localhost:8001
     predicates:
       - Method=GET,POST

2.8、路由断言 Query 配置

只有请求带了 token 参数才路由。

routes:
    - id: home-server # 路由的唯一标识
      uri: http://localhost:8001
      predicates:
        - Query=token

2.9、路由断言 RemoteAddr 配置

ip 后面的子网掩码没测试成功,带详查。

routes:
   - id: home-server # 路由的唯一标识
     uri: http://localhost:8001
     predicates:
       - RemoteAddr=192.168.1.12

2.10、路由断言 Weight 配置

80%的请求会路由到 8001, 20%的请求会路由到 8002。

routes:
    - id: home-server_high # 路由的唯一标识
      uri: http://localhost:8001
      predicates:
        - Weight=group1,8
    - id: home-server_low
      uri: http://localhost:8002
      predicates:
        - Weight=group1,2

测试结果:
打印出来日志验证,如下图:
可见 8001 访问日志为 8个,8002 为 2个。
8001访问日志
8002访问日志

3、启动类(忽略)

写这个完全是为了凑够篇幅,O(∩_∩)O哈哈~

@SpringBootApplication
public class GatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

五、Gateway 整合 Sentinel(熔断、限流)

5.1 引入依赖

在 Spring Cloud Alibaba 2.1.6之前的版本,引入的是 sentinel-spring-cloud-gateway-adapter 包,并且需要自己实现好多配置类,2.1.6 之后的版本内部已经帮我们实现好了,所以使用起来比较简单了。
版本由父pom控制。

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--2.1.6之前的版本是 adapter 的包,整合比较麻烦,需要写配置类-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>

5.2、配置 application.yml

需要 配置的是 gateway 和 sentinel

server:
  port: 8089 #服务端
spring:
  application:
    name: gateway-server
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:  #配置gateway
      discovery:
        locator:
          enabled: true #默认为false,true:开启通过微服务名访问
        enabled: true # 是否开启网关
    sentinel:  # 配置sentinel
      transport:
        dashboard: localhost:8080

5.3、sentinel 启动

sentinel 基本使用时比较简单的,只需要从官网下载并启动就可以使用了,默认端口(8080),用户名(sentinel)和密码(sentinel)启动成功如下:
sentinel启动控制页面

5.4、sentinel 配置限流规则

5.4.1、规则配置

以下配置说明:
API 名称:这个相当于一个服务的一个API的唯一ID;
阈值类型:1个 QPS 是完整的一次请求,发出请求并且拿到完成的请求结果;
QPS 阈值:每秒最大的QPS数;
间隔:请求间隔最大时间;
Burst size:宽容次数,比如我配置的是每秒访问3次以上进行流控,如果这个参数设置为 1 ,则每秒访问 4 次以上进行流控。
流控规则配置

5.4.2、测试结果

我用postman每秒请求3次以上,则返回 429 (429 是 Too Many Request 错误码)

流控

5.5、sentinel 配置熔断规则

5.5.1、配置路由

下面配置中:
配置的路由 id 是 home-server,lb 是 负载均衡配置。

spring:
  application:
    name: gateway-server
  cloud:
    nacos:
      config:
        namespace: 16201af3-217e-468c-bc9c-0f2a9ee04912
        server-addr: localhost:8848
        file-extension: yaml
      discovery:
        namespace: 16201af3-217e-468c-bc9c-0f2a9ee04912
        server-addr: localhost:8848
    sentinel:
      transport:
        port: 8719
        dashboard: localhost:8080
    gateway: #配置gateway
      routes:
        - id: home-server
          uri: lb://home-server
          predicates:
            - Path=/home/**

5.5.2、规则配置

以 异常数 降级来举例
熔断策略:以什么样的策略熔断;
慢调用比例:请求超过最大RT值,比如 1ms;
熔断时长:接口发生异常后熔断时长;
最小请求次数:每秒请求最少的失败次数;
统计时长:在一定的时间段内最少请求 2 次,每个请求超过1ms, 请求数量大于 50%;

熔断规则

5.5.3、测试结果

用 postman 快速发送请求,则会熔断,返回 DegradeException 异常,降级异常。

测试结果

5.5.4、自定义流控降级异常信息

5.5.4.1、 通过配置类配置

在 SentinelConfig 类中加入 init() 初始化方法(要用 @PostConstruct 注解进行初始化),定义异常处理提示信息即可。

@PostConstruct
    public void init(){
        BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                Map<String, String> result = new HashMap<>();
                result.put("code", HttpStatus.TOO_MANY_REQUESTS.toString());
                result.put("msg", "服务压力过大,请稍后重试!");
                return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS).contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(result));
            }
        };
        GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    }
5.5.4.2、通过application.yml 配置

主要配置 spring.cloud.sentinel.scg.fallback 即可。

spring:
  cloud:
    sentinel:
      transport:
        port: 8719
        dashboard: localhost:8080
      scg:
        fallback:
          mode: response
          response-body: '{"code":"429 TOO_MANY_REQUEST", "msg":"服务压力过大,请稍后重试!"}'
5.5.4.3、测试结果

配置服务流控或者降级,阈值设置为1(总之小一点),postman 快速发送请求返回自定义服务流控降级信息。

自定义提示信息

总结

如今的微服务可以说是互联网公司的开发必备了,因为互联网公司的业务、用户量、以及针对以后的扩展和功能添加等相对都比较高,所以微服务就是最好的不二之选。
Gateway呢就是各个微服务的入口了,也是公司后台服务的大门,也是公司后台服务安全的第一道防护(有可能上一次也可以做安全控制),学习并记录这一特技,技多不压身,挺好。
小生不才,感谢赏光!!!

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐