SpringCloud - Zuul路由网关使用详解

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
网络型负载均衡 NLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
简介: SpringCloud - Zuul路由网关使用详解

【1】Zuul是什么

Zuul是从设备和网站到Netflix流应用程序后端的所有请求的前门。作为边缘服务应用程序,Zuul旨在实现动态路由,监控,弹性和安全性。它还可以根据需要将请求路由到多个合适的服务弹性收缩组。

为什么创建Zuul?

Netflix API流量的数量和多样性有时会导致生产问题迅速而且没有任何警告。我们需要一个允许我们快速改变行为的系统,以便对这些情况做出反应。

Zuul使用一系列不同类型的过滤器,使我们能够快速灵活地将功能应用于我们的边缘服务。这些过滤器可帮助我们执行以下功能:

  • 身份验证和安全性 - 识别每个资源的身份验证要求并拒绝不满足这些要求的请求。
  • 洞察和监控 - 在边缘跟踪有意义的数据和统计数据,以便为我们提供准确的生产视图。
  • 动态路由 - 根据需要动态地将请求路由到不同的后端群集。
  • 压力测试 - 逐渐增加群集的流量以衡量性能。
  • Load Shedding - 为每种类型的请求分配容量并删除超过限制的请求。
  • 静态响应处理 - 直接在边缘构建一些响应,而不是将它们转发到内部集群
  • 多区域弹性 - 跨AWS区域路由请求,以使我们的ELB使用多样化,并使我们的优势更接近我们的成员。

综上,Zuul包含了对请求的路由和过滤两个最主要的功能。其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础。而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础。

uul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他微服务的消息,也即以后的微服务的访问都是通过Zuul跳转后获得。


【2】Zuul的基本配置

① 创建Module/microservicecloud-zuul-gateway-9527

pom依赖如下:

   <dependencies>
    <!-- zuul路由网关 -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-zuul</artifactId>
    </dependency>
    <!-- Eureka服务注册 -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
    <!-- actuator监控 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!-- hystrix熔断 -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-hystrix</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>
    <!-- 日常标配 -->
    <dependency>
      <groupId>com.web.springcloud</groupId>
      <artifactId>microservicecloud-api</artifactId>
      <version>${project.version}</version>
    </dependency>
    <!-- Boot依赖 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jetty</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <!-- 热部署插件 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>springloaded</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
    </dependency>
  </dependencies>

查看spring-cloud-starter-zuul依赖如下:

<dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-hystrix</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-ribbon</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-archaius</artifactId>
    </dependency>
    <dependency>
      <groupId>com.netflix.zuul</groupId>
      <artifactId>zuul-core</artifactId>
    </dependency>
  </dependencies>
  • spring-cloud-starter-hystrix:该依赖用来在网关服务中实现对微服务转发时候的保护机制,通过线程隔离和断路器,防止微服务的故障引发API网关资源无法释放,从而影响其他应用的对外服务。
  • spring-cloud-starter-ribbon:该依赖用来实现在网关服务进行路由转发时候的客户端负载均衡以及请求重试。
  • spring-boot-starter-actuator:该依赖用来提供常规的微服务管理端点。另外,在Spring Cloud Zuul中还特别提供了/routes端点来返回当前的所有路由规则。

② yml配置文件

server: 
  port: 9527
spring: 
  application:
    name: microservicecloud-zuul-gateway
eureka: 
  client: 
    service-url: 
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka  
  instance:
    instance-id: gateway-9527.com
    prefer-ip-address: true 
info:
  app.name: web-microcloud
  company.name: www.web.com
  build.artifactId: $project.artifactId$
  build.version: $project.version$

③ hosts文件修改

本地域名解析:

# spring cloud eureka
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
127.0.0.1 eureka7003.com
# spring cloud zuul
127.0.0.1 myzuul.com

④ 主启动类如下

@SpringBootApplication
@EnableZuulProxy
public class Zuul_9527_StartSpringCloudApp
{
  public static void main(String[] args)
  {
    SpringApplication.run(Zuul_9527_StartSpringCloudApp.class, args);
  }
}

此时整个项目架构如下图:


⑤ 测试

启动三个服务集群、服务提供者8001和路由9527。


不用路由直接测试:http://localhost:8001/dept/get/1

使用路由测试:http://myzuul.com:9527/microservicecloud-dept/dept/get/1

(默认使用服务名进行跳转)


【3】路由映射规则实例

如对访问http://myzuul.com:9527/microservicecloud-dept/dept/get/1请求进行转发和加固。


① 修改yml文件


配置对应的path和serviceId,符合/mydept/**规则的请求都会被转发到microservicecloud-dept服务的实例上。

zuul: 
  routes: 
    mydept.serviceId: microservicecloud-dept
    mydept.path: /mydept/**

此时,请求转变为http://myzuul.com:9527/mydept/dept/get/1。


此时将/microservicecloud-consumer-dept-feign启动,测试如下:

此时两种方式都可以访问:

http://myzuul.com:9527/microservicecloud-dept/dept/get/1

http://myzuul.com:9527/mydept/dept/get/1

上面配置方式就是面向服务的路由,根据配置的映射关系,网关将会转发到某个服务的实例上面。如果某个服务有多个实例,Zuul默认使用轮询的负载均衡策略。

当然也可以直接配置url:

zuul: 
  routes: 
    mydept.url: http://loclhost:8001/
    mydept.path: /mydept/**

该配置定义了发往API网关服务的请求中,所有符合/mydept/**规则的访问都将被路由转发到http://loclhost:8001/地址上。mydept是路由的名字可以任意定义,但是一组path和url映射关系的路由名要相同。不过通常建议使用面向服务的路由。

更简洁的面向服务路由配置

对于面向服务的路由配置,除了使用path与serviceId映射的配置方式之外,还有一种更简洁的配置方式:

    zuul.routes.<serviceId>=<path>

其中serviceId指定路由的具体服务名,path用来配置匹配的请求表达式。

zuul: 
  routes: 
    mydept.serviceId: microservicecloud-dept
    mydept.path: /mydept/**

等价于如下:

zuul.routes.microservicecloud-dept=/mydept/**


② 服务路由的默认规则

当我们为Spring Cloud Zuul构建的API网关服务引入Spring Cloud Eureka之后,它为Eureka中的每个服务都自动创建一个默认路由规则。这些默认路由规则的path会使用serviceId配置的服务名作为请求前缀。

zuul.routes.microservicecloud-dept.path=/microservicecloud-dept/**
zuul.routes.microservicecloud-dept.serviceId=microservicecloud-dept

由于默认情况下所有Eureka上的服务都会被Zuul自动地创建映射关系来进行路由,这会使得一些我们不希望对外开发的服务也可能被外部访问。这时就需要zuul.ignored-services参数来设置一个服务名匹配表达式来定义不自动创建路由的规则。


③ 如何忽略真实服务名?

  • 单服务忽略设置如下:
zuul: 
  ignored-services: microservicecloud-dept
  routes: 
    mydept.serviceId: microservicecloud-dept
    mydept.path: /mydept/**

此时访问http://myzuul.com:9527/microservicecloud-dept/dept/get/1将会出现Error page。http://myzuul.com:9527/mydept/dept/get/1 正常。


  • 忽略所有服务名
zuul: 
  ignored-services: "*"
  routes: 
    mydept.serviceId: microservicecloud-dept
    mydept.path: /mydept/**

这时Zuul将对所有的服务都不自动创建路由规则,在这种情况下,就要在配置文件中逐个为需要路由的服务添加映射规则,只有在配置文件中出现的映射规则会被创建路由,而从Eureka中获取的其他服务,Zuul将不会再为它们创建路由规则。


③ 设置请求统一前缀

zuul: 
  prefix: /web
  ignored-services: "*"
  routes: 
    mydept.serviceId: microservicecloud-dept
    mydept.path: /mydept/**


此时http://myzuul.com:9527/mydept/dept/get/1将不可访问,请求转变为http://myzuul.com:9527/web/mydept/dept/get/1。


④Zuul如何根据服务名找到URL?

其实API网关也是Eureka服务治理下的一个普通的微服务应用,它除了将自己注册到Eureka服务注册中心上之外,也会从注册中心获取所有服务以及它们的实例清单。。所以在Eureka的帮助下,API网关服务本身就已经维护了系统中所有的serviceId与实例地址的映射关系。当有外部请求到达api网关的时候,根据请求的URL路径找到最佳匹配的path规则,api网关就可以知道要将该请求路由到哪个具体的serviceId上去。


由于在API网关中已经知道serviceId对应服务实例的地址清单,那么只需要通过Ribbon的负载均衡策略,直接在这些清单中选择一个具体额实例进行转发就能完成路由工作。


【4】请求过滤

每个客户端用户请求微服务应用提供的接口时,它们的访问权限往往都有一定的限制,系统并不会将所有的微服务接口都对它们开发。为了实现对客户端请求的安全校验和权限控制,最简单的方法就是为每个微服务应用都实现一套用于校验签名和鉴别权限的过滤器或拦截器。而这种方法通常是不可取的,这样的实现方式会使得相似的校验逻辑代码被分散到了各个微服务中去,冗余代码的出现是我们不希望看到的。所以,比较好的做法是将这些校验逻辑剥离出去,构建出一个独立的鉴权服务。


最好的做法是通过前置的网关服务来完成这些非业务性质的校验。在请求到达的时候就完成校验和过滤。Zuul允许开发者在API网关上通过定义过滤器来实现对请求的拦截和过滤,实现的方法非常简单,我们只需要继承ZuulFilter抽象类并实现它定义的4个抽象函数就可以完成对请求的拦截和过滤了。


实例如下:

package com.web.springcloud;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
public class MyZuulFilter extends ZuulFilter {
  private static final Logger log = LoggerFactory.getLogger(MyZuulFilter.class);
/**
过滤器具体逻辑
*/
  @Override
  public Object run() {
    // TODO Auto-generated method stub
    RequestContext currentContext = RequestContext.getCurrentContext();
    HttpServletRequest request = currentContext.getRequest();
    log.info("send {} request to {}",request.getMethod(),request.getRequestURL().toString());
    Object accessToken = request.getParameter("accessToken");
    if (accessToken==null) {
      log.warn("access token is empty");
      currentContext.setSendZuulResponse(false);
      currentContext.setResponseStatusCode(401);
      return null;
    }
    log.info("access token ok");
    return null;
  }
/**
判断该过滤器是否需要被执行,这里返回true,将会对所有请求生效
*/
  @Override
  public boolean shouldFilter() {
    // TODO Auto-generated method stub
    return true;
  }
/**
过滤器的执行顺序。当请求在一个阶段中存在多个过滤器时,需要根据该方法返回的值来依次执行
*/
  @Override
  public int filterOrder() {
    // TODO Auto-generated method stub
    return 0;
  }
  @Override
  public String filterType() {
    // TODO Auto-generated method stub
    return "pre";
  }
}

主启动类添加bean:

@SpringBootApplication
@EnableZuulProxy
public class Zuul_9527_StartSpringCloudApp
{
  public static void main(String[] args)
  {
    SpringApplication.run(Zuul_9527_StartSpringCloudApp.class, args);
  }
  @Bean
  public MyZuulFilter myZuulFilter() {
    return new MyZuulFilter();
  }
}

filterType

过滤器的类型,它决定了过滤器在请求的哪个生命周期中执行。

  • pre:请求被路由之前执行;
  • route : 在路由请求时被调用;
  • error :处理请求时发生错误时被调用
  • post :在routing和error过滤器之后被调用;
  • static:for static responses see StaticResponseFilter。

图示如下:





目录
相关文章
|
15天前
|
监控 负载均衡 Java
深入理解Spring Cloud中的服务网关
深入理解Spring Cloud中的服务网关
|
1天前
|
JSON 前端开发 Java
SpringCloud怎么搭建GateWay网关&统一登录模块
本文来分享一下,最近我在自己的项目中实现的认证服务,目前比较简单,就是可以提供一个公共的服务,专门来处理登录请求,然后我还在API网关处实现了登录拦截的效果,因为在一个博客系统中,有一些地址是可以不登录的,比方说首页;也有一些是必须登录的,比如发布文章、评论等。所以,在网关处可以支持自定义一些不需要登录的地址,一些需要登录的地址,也可以在网关处进行校验,如果未登录,可以返回JSON格式的出参,前端可以进行相关处理,比如跳转到登录页面等。
|
15天前
|
Java API 开发工具
Spring Boot与Spring Cloud Config的集成
Spring Boot与Spring Cloud Config的集成
|
17天前
|
监控 负载均衡 Java
深入理解Spring Cloud中的服务网关
深入理解Spring Cloud中的服务网关
|
22天前
|
Java API 网络架构
Spring Boot与Spring Cloud Gateway的集成
Spring Boot与Spring Cloud Gateway的集成
|
23天前
|
负载均衡 监控 Java
深入理解Spring Boot与Spring Cloud的整合方式
深入理解Spring Boot与Spring Cloud的整合方式
|
26天前
|
Java API 开发者
Spring Cloud Gateway中的GlobalFilter:构建强大的API网关过滤器
Spring Cloud Gateway中的GlobalFilter:构建强大的API网关过滤器
29 0
|
27天前
|
Java Nacos 网络架构
Spring Cloud gateway 网关四 动态路由
Spring Cloud gateway 网关四 动态路由
|
1月前
|
人工智能 Java Spring
使用 Spring Cloud Alibaba AI 构建 RAG 应用
本文介绍了RAG(Retrieval Augmented Generation)技术,它结合了检索和生成模型以提供更准确的AI响应。示例中,数据集(包含啤酒信息)被加载到Redis矢量数据库,Spring Cloud Alibaba AI Starter用于构建一个Spring项目,演示如何在接收到用户查询时检索相关文档并生成回答。代码示例展示了数据加载到Redis以及RAG应用的工作流程,用户可以通过Web API接口进行交互。
52399 63
|
2天前
|
资源调度 Java 调度
Spring Cloud Alibaba 集成分布式定时任务调度功能
Spring Cloud Alibaba 发布了 Scheduling 任务调度模块 [#3732]提供了一套开源、轻量级、高可用的定时任务解决方案,帮助您快速开发微服务体系下的分布式定时任务。