微服务-API网关Zuul


1. Why

微服务为什么需要API网关, 因为在微服务架构中,后端服务往往不直接开放给客户端,而是通过一个API网关根据请求的url,
路由到相应的服务。当添加API网关后,在第三方客户端和后端服务之间就创建了一面墙,这面墙直接与调用方通信进行权限控制,而后将请求均衡分发给后台服务端。Spring Cloud提供了解决方案: zuul网关.
在这里插入图片描述
API网关为微服务架构中的服务提供了统一的访问入口,客户端通过API网关访问相关服务。API网关的定义类似于设计模式中的门面模式,它相当于整个微服务架构中的门面,所有客户端的访问都通过它来进行路由及过滤。它实现了请求路由、负载均衡、校验过滤、服务容错、服务聚合等功能

2. Zuul

2.1 简介

Zuul路由是微服务架构的不可或缺的一部分,提供动态路由,监控,弹性,安全等的边缘服务。
Zuul是Netflix出品的一个基于JVM路由和服务端的负载均衡器(微服务网关)。
主要功能有代理, 动态路由, 过滤器等.
Zuul的GitHub开源→
官网资料→
Zuul可以和Eureka, Ribbon, Hystrix等组件配合使用. 使用Eureka服务注册和发现的网关微服务架构图:

2.2 zuul能干嘛

路由, 过滤, 负载均衡, 灰度发布等.

灰度发布, 又称金丝雀发布.
起源是,矿井工人发现,金丝雀对瓦斯气体很敏感,矿工会在下井之前,先放一只金丝雀到井中,如
果金丝雀不叫了,就代表瓦斯浓度高。
在这里插入图片描述
在灰度发布开始后,先启动一个新版本应用,但是并不直接将流量切过来,而是测试人员对新版本进
行线上测试,启动的这个新版本应用,就是我们的金丝雀。如果没有问题,那么可以将少量的用户流
量导入到新版本上,然后再对新版本做运行状态观察,收集各种运行时数据,如果此时对新旧版本做
各种数据对比,就是所谓的A/B测试。新版本没什么问题,那么逐步扩大范围、流量,把所有用户都迁
移到新版本上面来。

路由功能负责将外部请求转发到具体的服务实例上去,是实现统一访问入口的基础.

3. Zuul网关微服务实践

创建网关微服务[microservicecloud-zuul-gateway]

3.1 导入依赖

导入zuuleureka客户端的依赖(网关服务本身也需要注册到Eureka)

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

3.2 启动类开启代理配置

启动类添加@EnableZuulProxy注解, 开启网关代理配置.

/**
 * zuul 网关启动类
 */
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy // 开启Zuul的代理配置
public class ZuulGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulGatewayApplication.class, args);
    }
}

3.3 编写配置

application.yml文件中添加注册到eureka的配置.

server:
  port: 10010
spring:
  application:
    name: zuul-gateway
### Eureka客户端配置
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://www.eureka01.com:7001/eureka,http://www.eureka02.com:7002/eureka,http://www.eureka03.com:7003/eureka
  instance:
    prefer-ip-address: true
    instance-id: zuul-gateway-01

3.4 配置路由规则

application.yml文件中配置路由规则, 路由规则的配置方式有好几种. 下面分别列出.

3.4.1 方式一

### zuul路由配置
### 路由映射配置方式1, 也是默认的配置
zuul:
  routes:
    microservicecloud-provider:
      path: /microservicecloud-provider
      serviceId: microservicecloud-provider
    microservicecloud-consumer:
      path: /microservicecloud-consumer
      serviceId: microservicecloud-consumer

提示:
转发的路径path和路由的微服务实例名称serviceId一致时, 完全可以省略zuul的动态路由配置. 也就是上面的是默认配置.
只有在配置文件中出现的映射规则会被创建路由,而从Eureka中获取的其他服务,zuul将不会为它们创建路由规则。

启动网关微服务后, 我们不再直接访问后端服务了, 而是通过网关微服务进行路由转发. 下面是默认路由配置的测试结果.
在这里插入图片描述

3.4.2 方式二

默认的路由配置规则在实际应用场景中, 也是存在问题的. 后端微服务的实例名称暴露在url中, 可能存在安全隐患. 下面通过自定义path的方式, 在请求的url中使用别名, 再由Zuul网关进行路由转发到后端具体的服务提供方.

### 路由映射配置方式2, 隐藏微服务名称,使用别名路径
zuul:
  routes:
    myprovider:
      path: /myprovider/**
      serviceId: microservicecloud-provider
    myconsumer:
      path: /myconsumer/**
      serviceId: microservicecloud-consumer

或者简化写法

### 路由映射配置方式2, 隐藏微服务名称,使用别名路径
zuul:
  routes:
    myprovider.path: /myprovider/**
    myprovider.serviceId: microservicecloud-provider

    myconsumer.path: /myconsumer/**
    myconsumer.serviceId: microservicecloud-consumer

路由映射配置使用自定义path后, 原来默认的路由映射规则也是生效的, 仍然可以通过上面的方式请求. 为了不暴露后端服务实例名称, 我们使用自定义path的url请求, 下面是测试结果.
在这里插入图片描述

3.4.3 方式三

使用更简洁的zuul.routes.<serviceId>=<path>配置方式 , 使用方式和测试效果与上面一样.

zuul.routes.microservicecloud-provider=/myprovider/**
zuul.routes.microservicecloud-consumer=/consumer/**

### 路由映射配置方式3, 简化版
zuul:
  routes:
    microservicecloud-provider: /myprovider/**
    microservicecloud-consumer: /consumer/**

3.5 Zuul网关配置补充

API网关在使用中, 也可以通过配置项过滤掉不想使用网关路由规则的微服务实例或path. 例如某些时候,
有一些服务我们不需要对外开放也被外部访问到了。这个时候我们可以使用zuul.ignore-services参数来设置一个服务名匹配表达式来定义不自动创建路由的规则。zuul在自动创建服务路由的时候会根据该表达式来进行判断,如果服务名匹配表达式,那么zuul将跳过该服务,不为其创建路由规则。
比如,设置为zuul.ignored-services='*',zuul将对所有的服务都不自动创建路由规则.

配置忽略服务

zuul:
 # 此处省略部分路由配置...
  ignored-services: microservicecloud-api # 忽略的微服务实例;  '*' 表示忽略所有的微服务路由
  ignored-patterns: /**/hello/** # 忽略的path

上面配置了为microservicecloud-api忽略(不创建路由规则), 过滤掉了该服务实例的路由.
那么 http://localhost:port/microservicecloud-api/**/**的url请求将不会被路由转发, 请求不通.

还可以给在请求网关的url中添加前缀支持.

zuul:
    # 此处省略部分路由配置...
    prefix: /gatewayto # 网关访问的前缀

配置前缀访问的测试效果.
在这里插入图片描述

3.6 Zuul网关负载均衡

由于Zuul自动集成了Ribbon和Hystrix,所以Zuul天生就有负载均衡和服务容错能力.
在这里插入图片描述

3.7 查看路由信息

检查不可以少的端点访问依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

添加端点暴露, 提交端点访问的配置

# 开启查看路由的端点
management:
  endpoints:
    web:
      exposure:
        include: 'routes'

重启zuul网关微服务, 访问 http://localhost:10010/actuator/routes , 可以查看路由信息.
在这里插入图片描述

4. Zuul过滤器

4.1 Zuul过滤器介绍

动态路由功能在真正运行时,它的路由映射请求转发都是由几个不同的Zuul过滤器完成的。
路由映射pre类型的过滤器完成,它将请求路径与配置的路由规则进行匹配,以找到需要转发的目标地址;
请求转发route类型的过滤器来完成,对pre类型过滤器获得的路由地址进行转发。
所以,Zuul过滤器可以说是Zuul实现API网关功能最为核心的部件。

4.2 Zuul过滤器-方法说明

(1) filterType:该函数需要返回一个字符串来代表过滤器的类型,而这个类型就是在HTTP请求过程中定义的各个阶段。在Zuul中
默认定义了四种不同生命周期的过滤器类型,具体如下:

  • pre:在请求被路由到目标服务前执行,比如权限校验、打印日志等功能;
  • route:在请求被路由到目标服务时执行.
  • post:在请求被路由到目标服务后执行,比如给目标服务的响应添加头信息,收集统计数据等功能;
  • error:请求在其他阶段发生错误时执行.

(2) filterOrder:通过int值来定义过滤器的执行顺序,数值越小优先级越高。

(3) shouldFilter:返回一个boolean类型来判断该过滤器是否要执行。我们可以通过此方法来指定过滤器的有效范围。

(4) run:过滤器的具体逻辑。在该函数中,我们可以实现自定义的过滤逻辑,来确定是否要拦截当前的请求,不对其进行后续的> 路由,或是在请求路由返回结果之后,对处理结果做一些加工等。

4.3 Zuul过滤器-生命周期

zuul过滤器
正常流程:

请求到达首先会经过pre过滤器进行请求路径与路由规则的映射, 而后到达routing过滤器进行路由转发, 请求就到达真正的服务提供者, 执行请求, 返回结果, 会到达post过滤器后, 完成响应.

异常流程:

  • 整个过程中, pre或者routing过滤器出现异常, 都会直接进入error过滤器, 在error过滤器处理完毕后, 会将请求交给post过滤器, 最后返回给用户.
  • 如果是error过滤器自己出现异常, 最终也会进入post过滤器, 然后返回给用户.
  • 如果是post过滤器出现异常, 会跳转到error过滤器, 但是与pre和routing过滤器不同的是, 请求不会再到达post过滤器, 而是直接返回给用户.

4.4 编写Zuul过滤器

Zuul网关的过滤器还可以做权限校验 异常处理等功能.
移步博客: 深入浅出SpringCloud→章节 6.5.4 编写Zuul过滤器


文章作者: 王子
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 王子 !
评论
  目录