SpringCloud 系列教程 | 第九篇: 服务网关 Zuul 初探
前面的文章我们介绍了, Eureka 用于服务的注册于发现, Feign 支持服务的调用以及均衡负载, Hystrix 处理服务的熔断防止故障扩散, Spring Cloud Config 服务集群配置中心, 似乎一个微服务框架已经完成了.
我们还是少考虑了一个问题, 外部的应用如何来访问内部各种各样的微服务呢? 在微服务架构中, 后端服务往往不直接开放给调用端, 而是通过一个 API 网关根据请求的 url, 路由到相应的服务. 当添加 API 网关后, 在第三方调用端和服务提供方之间就创建了一面墙, 这面墙直接与调用方通信进行权限控制, 后将请求均衡分发给后台服务端.
一个简单的微服务架构已经跃然纸面:
在 Spring Cloud 微服务系统中, 一种常见的负载均衡方式是, 客户端的请求首先经过负载均衡 (zuul,Ngnix,F5), 再到达服务网关 (zuul 集群), 然后再到具体的服务, 服务统一注册到高可用的服务注册中心集群, 服务的所有的配置文件由配置服务管理, 配置服务的配置文件放在 Git 仓库, 方便开发人员随时改配置.
1. 为什么需要 API Gateway?
1.1 简化客户端调用复杂度
在微服务架构模式下后端服务的实例数一般是动态的, 对于客户端而言很难发现动态改变的服务实例的访问地址信息. 因此在基于微服务的项目中为了简化前端的调用逻辑, 通常会引入 API Gateway 作为轻量级网关, 同时 API Gateway 中也会实现相关的认证逻辑从而简化内部服务之间相互调用的复杂度.
1.2 数据裁剪以及聚合
通常而言不同的客户端对于显示时对于数据的需求是不一致的, 比如手机端或者 web 端又或者在低延迟的网络环境或者高延迟的网络环境.
因此为了优化客户端的使用体验, API Gateway 可以对通用性的响应数据进行裁剪以适应不同客户端的使用需求. 同时还可以将多个 API 调用逻辑进行聚合, 从而减少客户端的请求数, 优化客户端用户体验
1.3 多渠道支持
当然我们还可以针对不同的渠道和客户端提供不同的 API Gateway, 对于该模式的使用由另外一个大家熟知的方式叫 Backend for front-end, 在 Backend for front-end 模式当中, 我们可以针对不同的客户端分别创建其 BFF, 进一步了解 BFF 可以参考这篇文章: Pattern: Backends For Frontends https://samnewman.io/patterns/architectural/bff/
1.4 遗留系统的微服务化改造
对于系统而言进行微服务改造通常是由于原有的系统存在或多或少的问题, 比如技术债务, 代码质量, 可维护性, 可扩展性等等. API Gateway 的模式同样适用于这一类遗留系统的改造, 通过微服务化的改造逐步实现对原有系统中的问题的修复, 从而提升对于原有业务响应力的提升. 通过引入抽象层, 逐步使用新的实现替换旧的实现.
在 Spring Cloud 体系中, Spring Cloud Zuul 就是提供负载均衡, 反向代理, 权限认证的一个 API gateway.
在开始聊 Zuul 如何使用之前, 先讲一个比较有意思的事情, 就是在 springcloud 组件中, 服务网关这个组件, springcloud 提供了两种选择, 一个是 netflix 公司开源的 Zuul, 还有一个是 springcloud 自己开源的 Spring Cloud Gateway, 具体这两个组件的恩怨情仇, 在后面的 Spring Cloud Gateway 的文章中我们再细聊:)
2. Spring Cloud Zuul
2.1 简单使用
Spring Cloud Zuul 路由是微服务架构的不可或缺的一部分, 提供动态路由, 监控, 弹性, 安全等的边缘服务. Zuul 是 Netflix 出品的一个基于 JVM 路由和服务端的负载均衡器.
下面我们来看一下 Zuul 最简单的使用方式, 创建 zuul-simple 工程
2.1 pom.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.1.6.RELEASE</version>
- <relativePath/> <!-- lookup parent from repository -->
- </parent>
- <groupId>com.springcloud</groupId>
- <artifactId>zuul-simple</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <name>zuul-simple</name>
- <description>Demo project for Spring Boot</description>
- <properties>
- <java.version>1.8</java.version>
- <spring-cloud.version>Greenwich.SR1</spring-cloud.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-dependencies</artifactId>
- <version>${spring-cloud.version}</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- </dependencies>
- </dependencyManagement>
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
- </project>
引入 spring-cloud-starter-netflix-zuul 包
2.2 配置文件 application.YAML
- server:
- port: 8080
- spring:
- application:
- name: spring-cloud-zuul
- zuul:
- routes:
- baidu:
- path: /baidu/**
- url: https://www.baidu.com/
这里的配置表示, 访问 / baidu/** 直接重定向到 https://www.baidu.com/**
如果直接访问 http://localhost:8080/baidu, 则会直接跳转到 https://www.baidu.com/.
2.3 启动类
- package com.springcloud.zuulsimple;
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
- @SpringBootApplication
- @EnableZuulProxy
- public class ZuulSimpleApplication {
- public static void main(String[] args) {
- SpringApplication.run(ZuulSimpleApplication.class, args);
- }
- }
启动类添加 @EnableZuulProxy, 支持网关路由.
史上最简单的 zuul 案例就配置完了
2.4 测试
启动项目, 在浏览器访问 http://localhost:8080/baidu/, 我们可以看到页面已经跳转到百度首页.
再尝试访问 http://localhost:8080/baidu/aa, 我们可以看到页面跳转至: https://www.baidu.com/search/error.html, 因为 https://www.baidu.com/aa 这个链接不存在, 所以百度帮我们跳转到的 error 页面.
至此, Zuul 简单使用已经介绍完毕, 下面我们来聊一下服务化的方式.
2.2 服务化
通过 url 映射的方式来实现 Zuul 的转发有局限性, 比如每增加一个服务就需要配置一条内容, 另外后端的服务如果是动态来提供, 就不能采用这种方案来配置了. 实际上在实现微服务架构时, 服务名与服务实例地址的关系在 eureka server 中已经存在了, 所以只需要将 Zuul 注册到 eureka server 上去发现其他服务, 就可以实现对 serviceId 的映射.
我们结合示例来说明, 在上面示例项目基础上来进行改造
2.2.1 添加依赖
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
- </dependency>
增加 spring-cloud-starter-netflix-eureka-client 包, 添加对 eureka 的支持.
2.2.2 配置文件 application.YAML
- server:
- port: 8080
- spring:
- application:
- name: spring-cloud-zuul
- zuul:
- routes:
- API-producer:
- path: /producer/**
- serviceId: spring-cloud-producer
- eureka:
- client:
- service-url:
- defaultZone: http://localhost:8761/eureka/
在这里我们增加了对服务的支持, 这里的 Zuul 配置的含义为访问 / producer/**, 转向到 eureka 上面 serviceId 为 spring-cloud-producer 的服务.
2.2.3 测试
先从上一篇的项目中 copy Eureka 到本篇的文件夹中, 再从第五篇的项目中 copy 一个 producer 到本篇的文件夹中.
依次启动 eureka,producer 和 Zuul.
我们打开浏览器访问: http://localhost:8080/producer/hello?name=spring, 可以看到页面正常显示 producer 的响应: hello spring,producer is ready. 说明通过 zuul 成功调用了 producer 服务.
这里 producer 可以启动两个服务, 多次刷新 http://localhost:8080/producer/hello?name=spring, 可以看到 Zuul 对服务的调用是负载均衡的.
2.3 网关的默认路由
但是如果后端服务多达十几个的时候, 每一个都这样配置也挺麻烦的, spring cloud zuul 已经帮我们做了默认配置. 默认情况下, Zuul 会代理所有注册到 Eureka Server 的微服务, 并且 Zuul 的路由规则如下: http://ZUUL_HOST:ZUUL_PORT / 微服务在 Eureka 上的 serviceId/** 会被转发到 serviceId 对应的微服务.
我们注销掉 zuul-simple 配置文件中有关路由的配置.
- #zuul:
- # routes:
- # API-producer:
- # path: /producer/**
- # serviceId: spring-cloud-producer
再次启动 Zuul.
我们在浏览器中访问 http://localhost:8080/spring-cloud-producer/hello?name=spring, 可以看到和上面一样的返回结果, 说明 Spring cloud zuul 默认已经提供了转发功能.
到此 zuul 的基本使用我们就聊完了. 关于 zuul 高级使用, 我们下篇再来介绍.
示例代码 - GitHub
参考:
- http://www.ityouknow.com/springcloud/2017/06/01/gateway-service-zuul.html
- https://www.fangzhipeng.com/springcloud/2018/08/05/sc-f5-zuul.html
来源: https://www.cnblogs.com/babycomeon/p/11142923.html