首页 > 技术文章 > SpringCloud-Zuul网关

dataoblogs 2020-11-22 12:40 原文

一、什么是网关

在微服务架构中,后端服务往往不直接开放给调用端,而是通过一个API网关根据请求的url,路由到相应的服务。API Gateway,是介于客户端和服务器端之间的中间层。当添加API网关后,在第三方调用端和服务提供方之间就创建了一面墙,这面墙直接与调用方通信,处理非业务功能,提供路由请求、鉴权、监控、缓存、限流等功能,然后将请求均衡分发给后台服务端。

二、为什么要使用网关

1、统一接入

统一接入的目的是简化客户端调用复杂度。在微服务架构模式下后端服务的实例数一般是动态的,对于客户端而言很难发现动态改变的服务实例的访问地址信息。因此在基于微服务的项目中为了简化前端的调用逻辑,通常会引入API Gateway作为轻量级网关.

  • 智能路由:通过判断路由接入不同的后端微服务
    /api/v1/order
    /api/v1/pay
    /api/v1/user
    api/v1/edu
  • 负载均衡:简历一组计算机节点提供相同的服务,将对服务的请求均匀的分摊到这些节点上
  • AB测试:不同的人群接入不同的版本,看哪一个的效果更好,例如接入不同的首页面风格,看哪一个更受欢迎
  • 灰度测试:灰度测试,就是在某项产品或应用正式发布前,选择特定人群试用,逐步扩大其试用者数量,以便及时发现和纠正其中的问题
  • 容灾处理:建立两套或多套功能相同的IT系统,互相之间可以进行健康状态监视和功能切换,当一处系统因意外(如火灾、地震等)停止工作时,整个应用系统可以切换到另一处,使得该系统功能可以继续正常工作。
  • 日志埋点:类似Nignx日志

2、流量监控

  • 限流处理:如果流量过大,可以再网关处进行阻断,不让过载的流量损害后端的服务
  • 服务降级:流量过大时关闭某些不重要的服务,节省出次要服务的访问流量

3、安全防护

  • 鉴权处理:登录认证
  • 监控:监控每个服务的运行状况
  • 机器网络隔离:通过网关暴露外网访问,其他微服务只允许网关通过内网访问,局域网内访问速度快,没有流量限制

4、数据裁剪以及聚合

不同的客户端对显示时数据的需求是不一致的,比如手机端或者Web端,低延迟的网络环境或者高延迟的网络环境。
为了优化客户端的使用体验,API Gateway可以对通用性的响应数据进行裁剪以适应不同客户端的使用需求。同时还可以将多个API调用逻辑进行聚合,从而减少客户端的请求数,优化客户端用户体验。

5、多渠道支持

当然我们还可以针对不同的渠道和客户端提供不同的API Gateway,对于该模式的使用由另外一个大家熟知的方式叫Backend for front-end, 在Backend for front-end模式当中,我们可以针对不同的客户端分别创建其BFF,进一步了解BFF可以参考这篇文章:Pattern: Backends For Frontends
BFF(用于前端的后端)

6、遗留系统的微服务化改造

对于系统系统而言进行微服务改造通常是由于原有的系统存在或多或少的问题,比如技术债务,代码质量,可维护性,可扩展性等等。API Gateway的模式同样适用于这一类遗留系统的改造,通过微服务化的改造逐步实现对原有系统中的问题的修复,从而提升对于原有业务响应力的提升。通过引入抽象层,逐步使用新的实现替换旧的实现。

二、主流的网关

  • 1、zuul 是Netflix开源的微服务网关,和Eureka,Ribbon,Hystrix等组件配合使用,Zuul
    2.0比1.0的性能提高很多。 在Spring Cloud体系中, Spring Cloud Zuul就是提供负载均衡、反向代理、权限认证的一个API gateway。
  • 2、kong
    由Mashape公司开源的,基于Nginx的API gateway
  • 3、nginx+lua(成本较高)
    是一个高性能的HTTP和反向代理服务器,lua是脚本语言,可以开发很多自定义模块,让Nginx执行Lua脚本,并且高并发、非阻塞的处理各种请求。例如京东使用的就是这种架构。

一、搭建Zuul服务

1、创建网关模块
Artifact:api_gateway
2、pom.xml依赖

<dependencies>
    <!--网关-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    </dependency>
</dependencies>

3、配置文件application.properties

server.port=9003
#服务的名称
spring.application.name=guliedu-api-gateway

### 配置URL 映射 ###
#这里的配置表示,访问path路径 直接重定向到url指定的地址
#如:访问        /edu/course/18(http://localhost:9003/edu/course/18)
#    重定向到    http://localhost:8081/edu/course/18

zuul.routes.api-edu.path=/edu/**
zuul.routes.api-edu.url=http://localhost:8082/edu/

4、创建启动类
启动类添加@EnableZuulProxy,支持网关路由。

@EnableZuulProxy注解中包含了断路器注解@EnableCircuitBreaker

package com.atguigu.guliedu.gateway;
@SpringBootApplication
@EnableZuulProxy
public class ApiGatewayApplication {

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

5、启动Zuul网关
6、通过网关访问微服务

例如:访问课程中心微服务

课程详情api:http://localhost:8082/edu/course/18
通过网关访问:http://localhost:9003/edu/course/18

通过url映射的方式来实现zull的转发有局限性,比如,每增加一个服务就需要配置一条内容,另外后端的服务如果是动态来提供(例如服务集群),就不能采用这种方案来配置了。

在实现微服务架构时,服务名与服务实例地址的关系在eureka server中已经存在了,所以只需要将Zuul注册到eureka server上去发现其他服务,就可以实现对serviceId的映射。

二、将网关服务化

服务化也就是将网关交给注册中心Eureka,可以被其他微服务发现并调用。

1、添加依赖
添加对Eureka的支持

<!--服务注册-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

2、添加配置
连接到注册中心,将自身注册为服务

#指定注册中心地址
eureka.client.service-url.defaultZone=http://127.0.0.1:9002/eureka/
#eureka服务器上获取的是服务器的ip地址,否则是主机名
eureka.instance.prefer-ip-address=true

3、注释掉zuul.routes的相关配置
4、启动Zuul网关

依次启动Eureka、edu和网关
5、通过网关访问微服务

例如:访问用户中心微服务

教学中心根据id获取讲师信息api:http://localhost:8082/edu/teacher/1
通过网关访问:http://localhost:9003/guliedu-edu/edu/teacher/1

网关的默认路由规则:

Zuul会代理所有注册到Eureka Server的微服务,并且Zuul的路由规则如下:

三、禁止通过网关访问某个服务

1、访问测试

依次启动Eureka、ucenter、statistics和网关
以下两个路径均可访问

2、环境隔离配置

目的是不想让某个或某些服务对外暴露接口
例如:统计分析微服务只提供给内网业务系统访问,不提供外网的网站和应用用户访问

环境隔离配置

禁止guliedu-statistics对外提供接口
zuul.ignored-services=guliedu-statistics
3、访问测试

内网可以访问:http://localhost:8084/admin/statistics/day/show-chart/2018-01-01/2019-01-01/login_num
网关不可以访问:http://localhost:9003/guliedu-statistics/admin/statistics/day/show-chart/2018-01-01/2019-01-01/login_num

四、禁止通过网关访问某些路由

1、访问测试
通过网关可以访问teacher模块的后台管理系统和网站的相关接口

后台接口:http://localhost:9003/guliedu-edu/admin/edu/teacher/1
网站接口:http://localhost:9003/guliedu-edu/edu/teacher/1
2、环境隔离配置

禁止通过网关访问路由

zuul.ignored-patterns=/**/admin/**
3、访问测试
网关不能访问所有包含 //admin/ 的路由

五、自定义路由映射

1、配置映射规则
可以通过我们定义的映射路径进行访问

自定义路由映射

zuul.routes.guliedu-edu=/edu-api/**
zuul.routes.guliedu-ucenter=/ucenter-api/**
zuul.routes.guliedu-oss=/oss-api/**
zuul.routes.guliedu-vod=/vod-api/**```
通过以下两种方式都可以访问
http://localhost:9003/guliedu-edu/edu/teacher/1
http://localhost:9003/edu-api/edu/teacher/1

六、网关默认不传递敏感信息

1、Ucenter中新建登录api


@PostMapping("login")
public R login(HttpServletRequest request){
    String token = request.getHeader("token");
    String cookie = request.getHeader("cookie");

    System.out.println(token);
    System.out.println(cookie);

    return R.ok();
}

2、postman中添加两个测试
测试1、不经过网关访问
在这里插入图片描述

在这里插入图片描述

测试2、经过网关访问
在这里插入图片描述

结论:
经过网关访问的请求,传输过程中cookie被过滤掉了

解决方案:
1、使用token
2、在配置文件中将请求头的过滤清除掉,使cookie可以向下游传递
#还原被网关过滤的请求头

zuul.sensitive-headers=

在这里插入图片描述

Filter有四个

  • PRE:发送请求,到达网关之前执行这个过滤器
  • ROUTING:发送请求,经过网关,没有达到服务器时,执行这个过滤器。
  • POST:发送请求经过网关,经过了服务器,执行这个过滤器。
  • ERROR:发生错误执行这个过滤器。

推荐阅读